Changeset 88709 in vbox
- Timestamp:
- Apr 26, 2021 4:38:03 PM (4 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Audio/DrvAudio.cpp
r88693 r88709 356 356 static void drvAudioStreamFree(PDRVAUDIOSTREAM pStream); 357 357 static int drvAudioStreamUninitInternal(PDRVAUDIO pThis, PDRVAUDIOSTREAM pStreamEx); 358 static int drvAudioStreamIterateInternal(PDRVAUDIO pThis, PDRVAUDIOSTREAM pStreamEx , bool fWorkMixBuf);358 static int drvAudioStreamIterateInternal(PDRVAUDIO pThis, PDRVAUDIOSTREAM pStreamEx); 359 359 static int drvAudioStreamPlayLocked(PDRVAUDIO pThis, PDRVAUDIOSTREAM pStreamEx, uint32_t *pcFramesPlayed); 360 360 static void drvAudioStreamDropInternal(PDRVAUDIO pThis, PDRVAUDIOSTREAM pStreamEx); … … 1215 1215 AssertReturn(pStreamEx->Core.uMagic == PDMAUDIOSTREAM_MAGIC, VERR_INVALID_MAGIC); 1216 1216 AssertReturn(pStreamEx->uMagic == DRVAUDIOSTREAM_MAGIC, VERR_INVALID_MAGIC); 1217 AssertMsg(pStreamEx->Core.enmDir == PDMAUDIODIR_OUT, 1218 ("Stream '%s' is not an output stream and therefore cannot be written to (direction is '%s')\n", 1219 pStreamEx->Core.szName, PDMAudioDirGetName(pStreamEx->Core.enmDir))); 1217 AssertMsgReturn(pStreamEx->Core.enmDir == PDMAUDIODIR_OUT, 1218 ("Stream '%s' is not an output stream and therefore cannot be written to (direction is '%s')\n", 1219 pStreamEx->Core.szName, PDMAudioDirGetName(pStreamEx->Core.enmDir)), VERR_ACCESS_DENIED); 1220 Assert(pStreamEx->fNoMixBufs); 1220 1221 1221 1222 AssertMsg(PDMAudioPropsIsSizeAligned(&pStreamEx->Guest.Cfg.Props, cbBuf), 1222 1223 ("Stream '%s' got a non-frame-aligned write (%RU32 bytes)\n", pStreamEx->Core.szName, cbBuf)); 1223 1224 1224 STAM_PROFILE_ADV_START(&pThis->Stats.DelayOut, out); /* (stopped in drvAudioStreamPlayLocked) */1225 /// @todo STAM_PROFILE_ADV_START(&pThis->Stats.DelayOut, out); /* (stopped in drvAudioStreamPlayLocked) */ 1225 1226 1226 1227 int rc = RTCritSectEnter(&pThis->CritSect); … … 1246 1247 * we're prebuffering. There will be no pfnStreamPlay call in this mode. 1247 1248 */ 1248 else if (pStreamEx->fNoMixBufs)1249 else 1249 1250 { 1250 1251 uint64_t offInternalBefore = pStreamEx->offInternal; RT_NOREF(offInternalBefore); … … 1256 1257 AudioHlpFileWrite(pStreamEx->Out.Dbg.pFilePlayNonInterleaved, pvBuf, *pcbWritten, 0 /* fFlags */); 1257 1258 } 1258 /*1259 * Legacy mode: Here we just dump the data in the guest side mixing buffer1260 * and then mixes it into the host side buffer. Later the device code will1261 * make a pfnStreamPlay call which recodes the data from the host side1262 * buffer and writes it to the host backend.1263 */1264 else1265 {1266 uint32_t cbWrittenTotal = 0;1267 1268 const uint32_t cbFree = AudioMixBufFreeBytes(&pStreamEx->Host.MixBuf);1269 if (cbFree < cbBuf)1270 LogRel2(("Audio: Lost audio output (%RU64ms, %RU32 free but needs %RU32) due to full host stream buffer '%s'\n",1271 PDMAudioPropsBytesToMilli(&pStreamEx->Host.Cfg.Props, cbBuf - cbFree), cbFree, cbBuf, pStreamEx->Core.szName));1272 1273 uint32_t cbToWrite = RT_MIN(cbBuf, cbFree);1274 if (cbToWrite)1275 {1276 /* We use the guest side mixing buffer as an intermediate buffer to do some1277 * (first) processing (if needed), so always write the incoming data at offset 0. */1278 uint32_t cFramesGstWritten = 0;1279 rc = AudioMixBufWriteAt(&pStreamEx->Guest.MixBuf, 0 /* offFrames */, pvBuf, cbToWrite, &cFramesGstWritten);1280 if (RT_SUCCESS(rc) && cFramesGstWritten > 0)1281 {1282 if (pThis->Out.Cfg.Dbg.fEnabled)1283 AudioHlpFileWrite(pStreamEx->Out.Dbg.pFileStreamWrite, pvBuf, cbToWrite, 0 /* fFlags */);1284 1285 uint32_t cFramesGstMixed = 0;1286 if (cFramesGstWritten)1287 {1288 int rc2 = AudioMixBufMixToParentEx(&pStreamEx->Guest.MixBuf, 0 /* cSrcOffset */,1289 cFramesGstWritten /* cSrcFrames */, &cFramesGstMixed /* pcSrcMixed */);1290 if (RT_SUCCESS(rc2))1291 {1292 const uint64_t tsNowNs = RTTimeNanoTS();1293 1294 Log3Func(("[%s] Writing %RU32 frames (%RU64ms)\n",1295 pStreamEx->Core.szName, cFramesGstWritten, PDMAudioPropsFramesToMilli(&pStreamEx->Guest.Cfg.Props, cFramesGstWritten)));1296 1297 Log3Func(("[%s] Last written %RU64ns (%RU64ms), now filled with %RU64ms -- %RU8%%\n",1298 pStreamEx->Core.szName, tsNowNs - pStreamEx->nsLastReadWritten,1299 (tsNowNs - pStreamEx->nsLastReadWritten) / RT_NS_1MS,1300 PDMAudioPropsFramesToMilli(&pStreamEx->Host.Cfg.Props, AudioMixBufUsed(&pStreamEx->Host.MixBuf)),1301 AudioMixBufUsed(&pStreamEx->Host.MixBuf) * 100 / AudioMixBufSize(&pStreamEx->Host.MixBuf)));1302 1303 pStreamEx->nsLastReadWritten = tsNowNs;1304 /* Keep going. */1305 }1306 else1307 {1308 AssertMsgFailed(("[%s] Mixing failed: cbToWrite=%RU32, cfWritten=%RU32, cfMixed=%RU32, rc=%Rrc\n",1309 pStreamEx->Core.szName, cbToWrite, cFramesGstWritten, cFramesGstMixed, rc2));1310 if (RT_SUCCESS(rc))1311 rc = rc2;1312 }1313 1314 cbWrittenTotal = AUDIOMIXBUF_F2B(&pStreamEx->Guest.MixBuf, cFramesGstWritten);1315 1316 STAM_COUNTER_ADD(&pThis->Stats.TotalFramesWritten, cFramesGstWritten);1317 STAM_COUNTER_ADD(&pThis->Stats.TotalFramesMixedOut, cFramesGstMixed);1318 Assert(cFramesGstWritten >= cFramesGstMixed);1319 STAM_COUNTER_ADD(&pThis->Stats.TotalFramesLostOut, cFramesGstWritten - cFramesGstMixed);1320 STAM_COUNTER_ADD(&pThis->Stats.TotalBytesWritten, cbWrittenTotal);1321 1322 STAM_COUNTER_ADD(&pStreamEx->Out.Stats.TotalFramesWritten, cFramesGstWritten);1323 STAM_COUNTER_INC(&pStreamEx->Out.Stats.TotalTimesWritten);1324 }1325 1326 Log3Func(("[%s] Dbg: cbBuf=%RU32, cbToWrite=%RU32, cfHstUsed=%RU32, cfHstfLive=%RU32, cFramesGstWritten=%RU32, "1327 "cFramesGstMixed=%RU32, cbWrittenTotal=%RU32, rc=%Rrc\n",1328 pStreamEx->Core.szName, cbBuf, cbToWrite, AudioMixBufUsed(&pStreamEx->Host.MixBuf),1329 AudioMixBufLive(&pStreamEx->Host.MixBuf), cFramesGstWritten, cFramesGstMixed, cbWrittenTotal, rc));1330 }1331 else1332 AssertMsgFailed(("[%s] Write failed: cbToWrite=%RU32, cFramesGstWritten=%RU32, rc=%Rrc\n",1333 pStreamEx->Core.szName, cbToWrite, cFramesGstWritten, rc));1334 }1335 else1336 rc = VERR_BUFFER_OVERFLOW;1337 *pcbWritten = cbWrittenTotal;1338 pStreamEx->offInternal += cbWrittenTotal;1339 }1340 1259 } 1341 1260 else … … 1397 1316 AssertRCReturn(rc, rc); 1398 1317 1399 rc = drvAudioStreamIterateInternal(pThis, pStreamEx , false /*fWorkMixBuf*/); /** @todo r=bird: why didn't it work the mixing buffer initially. We can probably set this to true... It may cause repeat work though. */1318 rc = drvAudioStreamIterateInternal(pThis, pStreamEx); 1400 1319 1401 1320 RTCritSectLeave(&pThis->CritSect); … … 1488 1407 * @param pThis Pointer to driver instance. 1489 1408 * @param pStreamEx Stream to iterate. 1490 * @param fWorkMixBuf Push data from the mixing buffer to the backend.1409 * 1491 1410 * @todo r=bird: Don't know why the default behavior isn't to push data into 1492 1411 * the backend... We'll never get out of the pending-disable state if 1493 1412 * the mixing buffer doesn't empty out. 1494 1413 */ 1495 static int drvAudioStreamIterateInternal(PDRVAUDIO pThis, PDRVAUDIOSTREAM pStreamEx , bool fWorkMixBuf)1414 static int drvAudioStreamIterateInternal(PDRVAUDIO pThis, PDRVAUDIOSTREAM pStreamEx) 1496 1415 { 1497 1416 AssertPtrReturn(pThis, VERR_INVALID_POINTER); … … 1539 1458 * should probably not be here at all. */ 1540 1459 uint32_t cFramesLive; 1541 if (pStreamEx->fNoMixBufs) 1542 { 1543 cFramesLive = pStreamEx->Out.cbPreBuffered; 1544 if (cFramesLive > 0) 1545 { 1546 uint32_t cbIgnored = 0; 1547 drvAudioStreamWriteNoMixBufs(pThis, pStreamEx, NULL, 0, &cbIgnored); 1548 cFramesLive = PDMAudioPropsBytesToFrames(&pStreamEx->Core.Props, pStreamEx->Out.cbPreBuffered); 1549 } 1550 } 1551 else 1552 { 1553 cFramesLive = AudioMixBufLive(&pStreamEx->Host.MixBuf); 1554 if (cFramesLive > 0 && fWorkMixBuf) 1555 { 1556 uint32_t cIgnored = 0; 1557 drvAudioStreamPlayLocked(pThis, pStreamEx, &cIgnored); 1558 1559 cFramesLive = AudioMixBufLive(&pStreamEx->Host.MixBuf); 1560 } 1460 cFramesLive = pStreamEx->Out.cbPreBuffered; 1461 if (cFramesLive > 0) 1462 { 1463 uint32_t cbIgnored = 0; 1464 drvAudioStreamWriteNoMixBufs(pThis, pStreamEx, NULL, 0, &cbIgnored); 1465 cFramesLive = PDMAudioPropsBytesToFrames(&pStreamEx->Core.Props, pStreamEx->Out.cbPreBuffered); 1561 1466 } 1562 1467 Log3Func(("[%s] cFramesLive=%RU32\n", pStreamEx->Core.szName, cFramesLive)); … … 1634 1539 if (pStreamEx->Core.fStatus & PDMAUDIOSTREAMSTS_FLAGS_PENDING_DISABLE) 1635 1540 { 1636 drvAudioStreamIterateInternal(pThis, pStreamEx , true /*fWorkMixBuf*/);1541 drvAudioStreamIterateInternal(pThis, pStreamEx); 1637 1542 1638 1543 if (pStreamEx->Core.fStatus & PDMAUDIOSTREAMSTS_FLAGS_PENDING_DISABLE) … … 1656 1561 } 1657 1562 1658 /**1659 * Worker for drvAudioStreamPlay that does the actual playing.1660 *1661 * @returns VBox status code.1662 * @param pThis The audio driver instance data.1663 * @param pStreamEx The stream to play.1664 * @param cFramesToPlay Number of audio frames to play. The backend is1665 * supposed to have buffer space for this.1666 * @param pcFramesPlayed Where to return the number of audio frames played.1667 */1668 static int drvAudioStreamPlayDoIt(PDRVAUDIO pThis, PDRVAUDIOSTREAM pStreamEx, uint32_t cFramesToPlay, uint32_t *pcFramesPlayed)1669 {1670 Assert(pStreamEx->Core.enmDir == PDMAUDIODIR_OUT);1671 1672 /*1673 * Push data to the host device.1674 */1675 int rc = VINF_SUCCESS;1676 uint32_t cFramesLeft = cFramesToPlay;1677 while (cFramesLeft > 0)1678 {1679 /*1680 * Grab a chunk of audio data in the backend format.1681 */1682 uint8_t abChunk[_4K];1683 uint32_t cFramesRead = 0;1684 rc = AudioMixBufAcquireReadBlock(&pStreamEx->Host.MixBuf, abChunk,1685 RT_MIN(sizeof(abChunk), AUDIOMIXBUF_F2B(&pStreamEx->Host.MixBuf, cFramesLeft)),1686 &cFramesRead);1687 AssertRCBreak(rc);1688 1689 uint32_t cbRead = AUDIOMIXBUF_F2B(&pStreamEx->Host.MixBuf, cFramesRead);1690 Assert(cbRead <= sizeof(abChunk));1691 1692 /*1693 * Feed it to the backend.1694 */1695 uint32_t cFramesPlayed = 0;1696 uint32_t cbPlayed = 0;1697 rc = pThis->pHostDrvAudio->pfnStreamPlay(pThis->pHostDrvAudio, pStreamEx->pBackend, abChunk, cbRead, &cbPlayed);1698 if (RT_SUCCESS(rc))1699 {1700 if (pThis->Out.Cfg.Dbg.fEnabled)1701 AudioHlpFileWrite(pStreamEx->Out.Dbg.pFilePlayNonInterleaved, abChunk, cbPlayed, 0 /* fFlags */);1702 1703 if (cbRead != cbPlayed)1704 LogRel2(("Audio: Host stream '%s' played wrong amount (%RU32 bytes read but played %RU32)\n",1705 pStreamEx->Core.szName, cbRead, cbPlayed));1706 1707 cFramesPlayed = AUDIOMIXBUF_B2F(&pStreamEx->Host.MixBuf, cbPlayed);1708 AssertStmt(cFramesLeft >= cFramesPlayed, cFramesPlayed = cFramesLeft);1709 cFramesLeft -= cFramesPlayed;1710 }1711 1712 AudioMixBufReleaseReadBlock(&pStreamEx->Host.MixBuf, cFramesPlayed);1713 1714 AssertRCBreak(rc); /* (this is here for Acquire/Release symmetry - which isn't at all necessary) */1715 AssertBreak(cbPlayed > 0); /* (ditto) */1716 }1717 1718 Log3Func(("[%s] Played %RU32/%RU32 frames, rc=%Rrc\n", pStreamEx->Core.szName, cFramesToPlay - cFramesLeft, cFramesToPlay, rc));1719 *pcFramesPlayed = cFramesToPlay - cFramesLeft;1720 return rc;1721 }1722 1723 /**1724 * Worker for drvAudioStreamPlay.1725 */1726 static int drvAudioStreamPlayLocked(PDRVAUDIO pThis, PDRVAUDIOSTREAM pStreamEx, uint32_t *pcFramesPlayed)1727 {1728 /*1729 * Zero the frame count so we can return at will.1730 */1731 *pcFramesPlayed = 0;1732 1733 PDMAUDIOSTREAMSTS fStrmStatus = pStreamEx->Core.fStatus;1734 #ifdef LOG_ENABLED1735 char szStreamSts[DRVAUDIO_STATUS_STR_MAX];1736 #endif1737 Log3Func(("[%s] Start fStatus=%s\n", pStreamEx->Core.szName, dbgAudioStreamStatusToStr(szStreamSts, fStrmStatus)));1738 1739 /*1740 * Operational?1741 */1742 if (pThis->pHostDrvAudio)1743 { /* likely? */ }1744 else1745 return VERR_PDM_NO_ATTACHED_DRIVER;1746 1747 if ( pThis->Out.fEnabled1748 && PDMAudioStrmStatusIsReady(fStrmStatus))1749 { /* likely? */ }1750 else1751 return VERR_AUDIO_STREAM_NOT_READY;1752 1753 /*1754 * Get number of frames in the mix buffer and do some logging.1755 */1756 uint32_t const cFramesLive = AudioMixBufLive(&pStreamEx->Host.MixBuf);1757 Log3Func(("[%s] Last played %'RI64 ns ago; filled with %u frm / %RU64 ms / %RU8%% total%s\n",1758 pStreamEx->Core.szName, pStreamEx->fThresholdReached ? RTTimeNanoTS() - pStreamEx->nsLastPlayedCaptured : -1, cFramesLive,1759 PDMAudioPropsFramesToMilli(&pStreamEx->Host.Cfg.Props, cFramesLive),1760 (100 * cFramesLive) / AudioMixBufSize(&pStreamEx->Host.MixBuf), pStreamEx->fThresholdReached ? "" : ", pre-buffering"));1761 1762 /*1763 * Restart pre-buffering if we're having a buffer-underrun.1764 */1765 if ( cFramesLive != 0 /* no underrun */1766 || !pStreamEx->fThresholdReached /* or still pre-buffering. */)1767 { /* likely */ }1768 else1769 {1770 /* It's not an underrun if the host audio driver still has an reasonable amount1771 buffered. We don't have a direct way of querying that, so instead we'll use1772 some heuristics based on number of writable bytes now compared to when1773 prebuffering ended the first time around. */1774 uint32_t cbBuffered = pThis->pHostDrvAudio->pfnStreamGetWritable(pThis->pHostDrvAudio, pStreamEx->pBackend);1775 if (cbBuffered < pStreamEx->Out.cbBackendMaxWritable)1776 cbBuffered = pStreamEx->Out.cbBackendMaxWritable - cbBuffered;1777 else1778 cbBuffered = 0;1779 uint32_t cbMinBuf = PDMAudioPropsMilliToBytes(&pStreamEx->Host.Cfg.Props, pStreamEx->Guest.Cfg.Device.cMsSchedulingHint * 2);1780 Log3Func(("Potential underrun: cbBuffered=%#x vs cbMinBuf=%#x\n", cbBuffered, cbMinBuf));1781 if (cbBuffered < cbMinBuf)1782 {1783 LogRel2(("Audio: Buffer underrun for stream '%s' (%RI64 ms since last call, %u buffered)\n",1784 pStreamEx->Core.szName, RTTimeNanoTS() - pStreamEx->nsLastPlayedCaptured, cbBuffered));1785 1786 /* Re-enter the pre-buffering stage again if enabled. */1787 if (pStreamEx->Host.Cfg.Backend.cFramesPreBuffering > 0)1788 {1789 pStreamEx->fThresholdReached = false;1790 STAM_REL_COUNTER_INC(&pThis->Out.StatsReBuffering);1791 }1792 }1793 }1794 1795 /*1796 * Work the pre-buffering.1797 *1798 * This is straight forward, the backend1799 */1800 uint32_t cbWritable;1801 bool fJustStarted = false;1802 if (pStreamEx->fThresholdReached)1803 {1804 /* not-prebuffering, likely after a while at least */1805 cbWritable = pThis->pHostDrvAudio->pfnStreamGetWritable(pThis->pHostDrvAudio, pStreamEx->pBackend);1806 }1807 else1808 {1809 /*1810 * Did we reach the backend's playback (pre-buffering) threshold?1811 * Can be 0 if no pre-buffering desired.1812 */1813 if (cFramesLive >= pStreamEx->Host.Cfg.Backend.cFramesPreBuffering)1814 {1815 LogRel2(("Audio: Stream '%s' buffering complete!\n", pStreamEx->Core.szName));1816 pStreamEx->fThresholdReached = fJustStarted = true;1817 }1818 /*1819 * Some audio files are shorter than the pre-buffering level (e.g. the1820 * "click" Explorer sounds on some Windows guests), so make sure that we1821 * also play those by checking if the stream already is pending disable1822 * mode, even if we didn't hit the pre-buffering watermark yet.1823 *1824 * Try play "Windows Navigation Start.wav" on Windows 7 (2824 samples).1825 */1826 else if ( cFramesLive > 01827 && (pStreamEx->Core.fStatus & PDMAUDIOSTREAMSTS_FLAGS_PENDING_DISABLE))1828 {1829 LogRel2(("Audio: Stream '%s' buffering complete (short sound)!\n", pStreamEx->Core.szName));1830 pStreamEx->fThresholdReached = fJustStarted = true;1831 }1832 /*1833 * Not yet, so still buffering audio data.1834 */1835 else1836 {1837 LogRel2(("Audio: Stream '%s' is buffering (%RU8%% complete)...\n",1838 pStreamEx->Core.szName, (100 * cFramesLive) / pStreamEx->Host.Cfg.Backend.cFramesPreBuffering));1839 return VINF_SUCCESS;1840 }1841 1842 /* Hack alert! This is for the underrun detection. */1843 cbWritable = pThis->pHostDrvAudio->pfnStreamGetWritable(pThis->pHostDrvAudio, pStreamEx->pBackend);1844 if (cbWritable > pStreamEx->Out.cbBackendMaxWritable)1845 pStreamEx->Out.cbBackendMaxWritable = cbWritable;1846 }1847 pStreamEx->Out.Stats.cbBackendWritableBefore = cbWritable;1848 1849 /*1850 * Figure out how much to play now.1851 * Easy, as much as the host audio backend will allow us to.1852 */1853 uint32_t cFramesWritable = PDMAUDIOPCMPROPS_B2F(&pStreamEx->Host.Cfg.Props, cbWritable);1854 uint32_t cFramesToPlay = cFramesWritable;1855 if (cFramesToPlay > cFramesLive) /* Don't try to play more than available, we don't want to block. */1856 cFramesToPlay = cFramesLive;1857 1858 Log3Func(("[%s] Playing %RU32 frames (%RU64 ms), now filled with %RU64 ms -- %RU8%%\n",1859 pStreamEx->Core.szName, cFramesToPlay, PDMAudioPropsFramesToMilli(&pStreamEx->Host.Cfg.Props, cFramesToPlay),1860 PDMAudioPropsFramesToMilli(&pStreamEx->Host.Cfg.Props, AudioMixBufUsed(&pStreamEx->Host.MixBuf)),1861 AudioMixBufUsed(&pStreamEx->Host.MixBuf) * 100 / AudioMixBufSize(&pStreamEx->Host.MixBuf)));1862 1863 /*1864 * Do the playing if we decided to play something.1865 */1866 int rc;1867 if (cFramesToPlay)1868 {1869 rc = drvAudioStreamPlayDoIt(pThis, pStreamEx, cFramesToPlay, pcFramesPlayed);1870 1871 pStreamEx->nsLastPlayedCaptured = RTTimeNanoTS();1872 pStreamEx->Out.Stats.cbBackendWritableAfter = pThis->pHostDrvAudio->pfnStreamGetWritable(pThis->pHostDrvAudio,1873 pStreamEx->pBackend);1874 }1875 else1876 rc = VINF_SUCCESS;1877 1878 Log3Func(("[%s] Live=%RU32 fr (%RU64 ms) Period=%RU32 fr (%RU64 ms) Writable=%RU32 fr (%RU64 ms) -> ToPlay=%RU32 fr (%RU64 ms) Played=%RU32 fr (%RU64 ms)%s\n",1879 pStreamEx->Core.szName,1880 cFramesLive, PDMAudioPropsFramesToMilli(&pStreamEx->Host.Cfg.Props, cFramesLive),1881 pStreamEx->Host.Cfg.Backend.cFramesPeriod,1882 PDMAudioPropsFramesToMilli(&pStreamEx->Host.Cfg.Props, pStreamEx->Host.Cfg.Backend.cFramesPeriod),1883 cFramesWritable, PDMAudioPropsFramesToMilli(&pStreamEx->Host.Cfg.Props, cFramesWritable),1884 cFramesToPlay, PDMAudioPropsFramesToMilli(&pStreamEx->Host.Cfg.Props, cFramesToPlay),1885 *pcFramesPlayed, PDMAudioPropsFramesToMilli(&pStreamEx->Host.Cfg.Props, *pcFramesPlayed),1886 fJustStarted ? "just-started" : ""));1887 RT_NOREF(fJustStarted);1888 1889 if (RT_SUCCESS(rc))1890 {1891 AudioMixBufFinish(&pStreamEx->Host.MixBuf, *pcFramesPlayed);1892 1893 STAM_PROFILE_ADV_STOP(&pThis->Stats.DelayOut, out);1894 STAM_COUNTER_ADD(&pThis->Stats.TotalFramesOut, *pcFramesPlayed);1895 STAM_COUNTER_ADD(&pStreamEx->Out.Stats.TotalFramesPlayed, *pcFramesPlayed);1896 STAM_COUNTER_INC(&pStreamEx->Out.Stats.TotalTimesPlayed);1897 }1898 return rc;1899 }1900 1901 1563 1902 1564 /** … … 1905 1567 static DECLCALLBACK(int) drvAudioStreamPlay(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream, uint32_t *pcFramesPlayed) 1906 1568 { 1907 PDRVAUDIO pThis = RT_FROM_MEMBER(pInterface, DRVAUDIO, IAudioConnector); 1908 AssertPtr(pThis); 1909 PDRVAUDIOSTREAM pStreamEx = (PDRVAUDIOSTREAM)pStream; 1910 AssertPtrReturn(pStreamEx, VERR_INVALID_POINTER); 1911 AssertPtrNullReturn(pcFramesPlayed, VERR_INVALID_POINTER); 1912 AssertReturn(pStreamEx->Core.uMagic == PDMAUDIOSTREAM_MAGIC, VERR_INVALID_MAGIC); 1913 AssertReturn(pStreamEx->uMagic == DRVAUDIOSTREAM_MAGIC, VERR_INVALID_MAGIC); 1914 AssertMsg(pStreamEx->Core.enmDir == PDMAUDIODIR_OUT, 1915 ("Stream '%s' is not an output stream and therefore cannot be played back (direction is 0x%x)\n", 1916 pStreamEx->Core.szName, pStreamEx->Core.enmDir)); 1917 AssertReturn(!pStreamEx->fNoMixBufs, VERR_INVALID_FUNCTION); 1918 1919 int rc = RTCritSectEnter(&pThis->CritSect); 1920 AssertRCReturn(rc, rc); 1921 1922 uint32_t cFramesPlayed = 0; 1923 rc = drvAudioStreamPlayLocked(pThis, pStreamEx, &cFramesPlayed); 1924 1925 RTCritSectLeave(&pThis->CritSect); 1926 1927 if (RT_SUCCESS(rc) && pcFramesPlayed) 1928 *pcFramesPlayed = cFramesPlayed; 1929 1930 if (RT_FAILURE(rc)) 1931 LogFlowFunc(("[%s] Failed with %Rrc\n", pStreamEx->Core.szName, rc)); 1932 return rc; 1933 } 1569 RT_NOREF(pInterface, pStream, pcFramesPlayed); 1570 AssertFailed(/* OBSOLETE! */); 1571 return VERR_NOT_SUPPORTED; 1572 } 1573 1934 1574 1935 1575 /** … … 2845 2485 if (!(fFlags & PDMAUDIOSTREAM_CREATE_F_NO_MIXBUF)) 2846 2486 { 2487 Assert(pCfgHost->enmDir == PDMAUDIODIR_IN); 2847 2488 rc = AudioMixBufInit(&pStreamEx->Host.MixBuf, pStreamEx->Core.szName, &CfgHostAcq.Props, CfgHostAcq.Backend.cFramesBufferSize); 2848 2489 AssertRCReturn(rc, rc); … … 2878 2519 if (!(fFlags & PDMAUDIOSTREAM_CREATE_F_NO_MIXBUF)) 2879 2520 { 2521 Assert(pCfgHost->enmDir == PDMAUDIODIR_IN); 2880 2522 rc = AudioMixBufInit(&pStreamEx->Guest.MixBuf, pStreamEx->Core.szName, &pCfgGuest->Props, CfgHostAcq.Backend.cFramesBufferSize); 2881 2523 AssertRCReturn(rc, rc); … … 2887 2529 if (!(fFlags & PDMAUDIOSTREAM_CREATE_F_NO_MIXBUF)) 2888 2530 { 2889 if (pCfgGuest->enmDir == PDMAUDIODIR_IN) 2890 { 2891 /* Host (Parent) -> Guest (Child). */ 2892 rc = AudioMixBufLinkTo(&pStreamEx->Host.MixBuf, &pStreamEx->Guest.MixBuf); 2893 AssertRC(rc); 2894 } 2895 else 2896 { 2897 /* Guest (Parent) -> Host (Child). */ 2898 rc = AudioMixBufLinkTo(&pStreamEx->Guest.MixBuf, &pStreamEx->Host.MixBuf); 2899 AssertRC(rc); 2900 } 2531 Assert(pCfgHost->enmDir == PDMAUDIODIR_IN); 2532 /* Host (Parent) -> Guest (Child). */ 2533 rc = AudioMixBufLinkTo(&pStreamEx->Host.MixBuf, &pStreamEx->Guest.MixBuf); 2534 AssertRC(rc); 2901 2535 } 2902 2536 … … 2910 2544 if (!(fFlags & PDMAUDIOSTREAM_CREATE_F_NO_MIXBUF)) 2911 2545 { 2546 Assert(pCfgHost->enmDir == PDMAUDIODIR_IN); 2912 2547 PDMDrvHlpSTAMRegisterF(pDrvIns, &pStreamEx->Host.MixBuf.cFrames, STAMTYPE_U32, STAMVISIBILITY_USED, STAMUNIT_NONE, 2913 2548 "Host side: The size of the mixer buffer (in frames)", "%s/1-HostMixBufSize", pStreamEx->Core.szName); 2914 2549 PDMDrvHlpSTAMRegisterF(pDrvIns, &pStreamEx->Guest.MixBuf.cFrames, STAMTYPE_U32, STAMVISIBILITY_USED, STAMUNIT_NONE, 2915 2550 "Guest side: The size of the mixer buffer (in frames)", "%s/2-GuestMixBufSize", pStreamEx->Core.szName); 2916 if (pCfgGuest->enmDir == PDMAUDIODIR_IN) 2917 { 2918 PDMDrvHlpSTAMRegisterF(pDrvIns, &pStreamEx->Host.MixBuf.cMixed, STAMTYPE_U32, STAMVISIBILITY_USED, STAMUNIT_NONE, 2919 "Host side: Number of frames in the mixer buffer", "%s/1-HostMixBufUsed", pStreamEx->Core.szName); 2920 PDMDrvHlpSTAMRegisterF(pDrvIns, &pStreamEx->Guest.MixBuf.cUsed, STAMTYPE_U32, STAMVISIBILITY_USED, STAMUNIT_NONE, 2921 "Guest side: Number of frames in the mixer buffer", "%s/2-GuestMixBufUsed", pStreamEx->Core.szName); 2922 } 2923 else 2924 { 2925 PDMDrvHlpSTAMRegisterF(pDrvIns, &pStreamEx->Host.MixBuf.cUsed, STAMTYPE_U32, STAMVISIBILITY_USED, STAMUNIT_NONE, 2926 "Host side: Number of frames in the mixer buffer", "%s/1-HostMixBufUsed", pStreamEx->Core.szName); 2927 PDMDrvHlpSTAMRegisterF(pDrvIns, &pStreamEx->Guest.MixBuf.cMixed, STAMTYPE_U32, STAMVISIBILITY_USED, STAMUNIT_NONE, 2928 "Guest side: Number of frames in the mixer buffer", "%s/2-GuestMixBufUsed", pStreamEx->Core.szName); 2929 } 2551 PDMDrvHlpSTAMRegisterF(pDrvIns, &pStreamEx->Host.MixBuf.cMixed, STAMTYPE_U32, STAMVISIBILITY_USED, STAMUNIT_NONE, 2552 "Host side: Number of frames in the mixer buffer", "%s/1-HostMixBufUsed", pStreamEx->Core.szName); 2553 PDMDrvHlpSTAMRegisterF(pDrvIns, &pStreamEx->Guest.MixBuf.cUsed, STAMTYPE_U32, STAMVISIBILITY_USED, STAMUNIT_NONE, 2554 "Guest side: Number of frames in the mixer buffer", "%s/2-GuestMixBufUsed", pStreamEx->Core.szName); 2930 2555 } 2931 2556 if (pCfgGuest->enmDir == PDMAUDIODIR_IN) … … 2996 2621 AssertReturn(pCfgHost->enmDir == pCfgGuest->enmDir, VERR_MISMATCH); 2997 2622 AssertReturn(pCfgHost->enmDir == PDMAUDIODIR_IN || pCfgHost->enmDir == PDMAUDIODIR_OUT, VERR_NOT_SUPPORTED); 2623 /* Require PDMAUDIOSTREAM_CREATE_F_NO_MIXBUF for output streams: */ 2624 AssertReturn((fFlags & PDMAUDIOSTREAM_CREATE_F_NO_MIXBUF) || pCfgHost->enmDir == PDMAUDIODIR_IN, VERR_INVALID_FLAGS); 2998 2625 2999 2626 /*
Note:
See TracChangeset
for help on using the changeset viewer.