Changeset 89327 in vbox for trunk/src/VBox/Devices/Audio
- Timestamp:
- May 28, 2021 12:22:27 AM (4 years ago)
- svn:sync-xref-src-repo-rev:
- 144676
- Location:
- trunk/src/VBox/Devices/Audio
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Audio/AudioMixer.cpp
r89314 r89327 611 611 */ 612 612 PPDMAUDIOSTREAM pStream; 613 rc = pConn->pfnStreamCreate(pConn, pSink->enmDir == PDMAUDIODIR_OUT ? PDMAUDIOSTREAM_CREATE_F_NO_MIXBUF : 0, 614 &CfgHost, pCfg, &pStream); 613 rc = pConn->pfnStreamCreate(pConn, 0 /*fFlags*/, &CfgHost, pCfg, &pStream); 615 614 if (RT_SUCCESS(rc)) 616 615 { … … 1445 1444 PPDMIAUDIOCONNECTOR const pIConnector = pMixStream->pConn; 1446 1445 PPDMAUDIOSTREAM const pStream = pMixStream->pStream; 1447 uint32_t cIgnored = 0;1448 pIConnector->pfnStreamCapture(pIConnector, pStream, &cIgnored);1449 1446 pIConnector->pfnStreamIterate(pIConnector, pStream); 1450 1447 … … 1461 1458 if (cFramesToRead > cFrames && !pMixStream->fUnreliable) 1462 1459 { 1463 Log4Func(("%s: cFramesToRead %u -> %u; %s (%u bytes writable)\n",1460 Log4Func(("%s: cFramesToRead %u -> %u; %s (%u bytes readable)\n", 1464 1461 pSink->pszName, cFramesToRead, cFrames, pMixStream->pszName, cbReadable)); 1465 1462 cFramesToRead = cFrames; … … 1606 1603 if (cbSrcToRead > 0) 1607 1604 { 1608 int rc2 = pIConnector->pfnStream Read(pIConnector, pStream, pvBuf, cbSrcToRead, &cbSrcRead);1605 int rc2 = pIConnector->pfnStreamCapture(pIConnector, pStream, pvBuf, cbSrcToRead, &cbSrcRead); 1609 1606 Log3Func(("%s: %#x L %#x => %#x bytes; rc2=%Rrc %s\n", 1610 1607 pSink->pszName, offSrc, cbSrcToRead, cbSrcRead, rc2, pMixStream->pszName)); -
trunk/src/VBox/Devices/Audio/DrvAudio.cpp
r89282 r89327 103 103 /** The stream's audio configuration. */ 104 104 PDMAUDIOSTREAMCFG Cfg; 105 /** This stream's mixing buffer. */106 AUDIOMIXBUF MixBuf;107 105 } DRVAUDIOSTREAMCTX; 106 107 /** 108 * Capture state of a stream wrt backend. 109 */ 110 typedef enum DRVAUDIOCAPTURESTATE 111 { 112 /** Invalid zero value. */ 113 DRVAUDIOCAPTURESTATE_INVALID = 0, 114 /** No capturing or pre-buffering. */ 115 DRVAUDIOCAPTURESTATE_NO_CAPTURE, 116 /** Regular capturing. */ 117 DRVAUDIOCAPTURESTATE_CAPTURING, 118 /** Returning silence till the backend buffer has reched the configured 119 * pre-buffering level. */ 120 DRVAUDIOCAPTURESTATE_PREBUF, 121 /** End of valid values. */ 122 DRVAUDIOCAPTURESTATE_END 123 } DRVAUDIOCAPTURESTATE; 108 124 109 125 /** … … 166 182 PPDMAUDIOBACKENDSTREAM pBackend; 167 183 168 /** Do not use the mixing buffers (Guest::MixBuf, Host::MixBuf). */169 bool fNoMixBufs;170 184 /** Set if pfnStreamCreate returned VINF_AUDIO_STREAM_ASYNC_INIT_NEEDED. */ 171 185 bool fNeedAsyncInit; 172 186 /** The fImmediate parameter value for pfnStreamDestroy. */ 173 187 bool fDestroyImmediate; 174 bool fPadding;188 bool afPadding[2]; 175 189 176 190 /** Number of (re-)tries while re-initializing the stream. */ … … 181 195 PDMHOSTAUDIOSTREAMSTATE enmLastBackendState; 182 196 197 /** The pre-buffering threshold expressed in bytes. */ 198 uint32_t cbPreBufThreshold; 199 183 200 /** The pfnStreamInitAsync request handle. */ 184 201 PRTREQ hReqInitAsync; 185 202 203 /** @todo The guest and host fields only contains the stream config now that 204 * the mixing buffer is gone, so we can probably combine them into a 205 * single Cfg member. */ 186 206 /** The guest side of the stream. */ 187 207 DRVAUDIOSTREAMCTX Guest; … … 189 209 DRVAUDIOSTREAMCTX Host; 190 210 211 212 /** The nanosecond timestamp when the stream was started. */ 213 uint64_t nsStarted; 214 /** Internal stream position (as per pfnStreamPlay/pfnStreamCapture). */ 215 uint64_t offInternal; 191 216 192 217 /** Timestamp (in ns) since last trying to re-initialize. … … 200 225 * write (output streams). */ 201 226 uint64_t nsLastReadWritten; 202 /** Internal stream position (as per pfnStreamWrite/Read). */ 203 uint64_t offInternal; 227 204 228 205 229 /** Union for input/output specifics depending on enmDir. */ … … 211 235 struct 212 236 { 237 /** The capture state. */ 238 DRVAUDIOCAPTURESTATE enmCaptureState; 239 213 240 struct 214 241 { 215 /** File for writing stream reads. */216 PAUDIOHLPFILE pFileStreamRead;217 242 /** File for writing non-interleaved captures. */ 218 PAUDIOHLPFILE pFileCapture NonInterleaved;243 PAUDIOHLPFILE pFileCapture; 219 244 } Dbg; 220 245 struct 221 246 { 247 uint32_t cbBackendReadableBefore; 248 uint32_t cbBackendReadableAfter; 249 222 250 STAMCOUNTER TotalFramesCaptured; 223 251 STAMCOUNTER AvgFramesCaptured; … … 236 264 struct 237 265 { 238 /** File for writing stream writes. */239 PAUDIOHLPFILE pFileStreamWrite;240 266 /** File for writing stream playback. */ 241 PAUDIOHLPFILE pFilePlay NonInterleaved;267 PAUDIOHLPFILE pFilePlay; 242 268 } Dbg; 243 269 struct … … 255 281 /** Number of bytes we've pre-buffered. */ 256 282 uint32_t cbPreBuffered; 257 /** The pre-buffering threshold expressed in bytes. */258 uint32_t cbPreBufThreshold;259 283 /** The play state. */ 260 284 DRVAUDIOPLAYSTATE enmPlayState; … … 467 491 468 492 /** 469 * Get p re-bufferstate name string.493 * Get play state name string. 470 494 */ 471 495 static const char *drvAudioPlayStateName(DRVAUDIOPLAYSTATE enmState) … … 487 511 } 488 512 513 514 /** 515 * Get capture state name string. 516 */ 517 static const char *drvAudioCaptureStateName(DRVAUDIOCAPTURESTATE enmState) 518 { 519 switch (enmState) 520 { 521 case DRVAUDIOCAPTURESTATE_INVALID: return "INVALID"; 522 case DRVAUDIOCAPTURESTATE_NO_CAPTURE: return "NO_CAPTURE"; 523 case DRVAUDIOCAPTURESTATE_CAPTURING: return "CAPTURING"; 524 case DRVAUDIOCAPTURESTATE_PREBUF: return "PREBUF"; 525 case DRVAUDIOCAPTURESTATE_END: 526 break; 527 } 528 return "BAD"; 529 } 530 531 489 532 /** 490 533 * Checks if the stream status is one that can be read from. … … 588 631 PDMHOSTAUDIOSTREAMSTATE enmOldState) 589 632 { 590 PDMAUDIODIR const enmDir= pStreamEx->Guest.Cfg.enmDir;633 PDMAUDIODIR const enmDir = pStreamEx->Guest.Cfg.enmDir; 591 634 #ifdef LOG_ENABLED 592 DRVAUDIOPLAYSTATE const enmPlayState = enmDir == PDMAUDIODIR_OUT ? pStreamEx->Out.enmPlayState : DRVAUDIOPLAYSTATE_INVALID; 635 DRVAUDIOPLAYSTATE const enmPlayState = enmDir == PDMAUDIODIR_OUT 636 ? pStreamEx->Out.enmPlayState : DRVAUDIOPLAYSTATE_INVALID; 637 DRVAUDIOCAPTURESTATE const enmCaptureState = enmDir == PDMAUDIODIR_OUT 638 ? pStreamEx->In.enmCaptureState : DRVAUDIOCAPTURESTATE_INVALID; 593 639 #endif 594 640 Assert(enmNewState != enmOldState); … … 611 657 drvAudioStreamProcessBackendStateChangeWasDraining(pStreamEx); 612 658 if (enmDir == PDMAUDIODIR_OUT) 613 pStreamEx->Out.enmPlayState = DRVAUDIOPLAYSTATE_NOPLAY; 659 pStreamEx->Out.enmPlayState = DRVAUDIOPLAYSTATE_NOPLAY; 660 else 661 pStreamEx->In.enmCaptureState = DRVAUDIOCAPTURESTATE_NO_CAPTURE; 614 662 break; 615 663 … … 660 708 PDMHostAudioStreamStateGetName(enmNewState), drvAudioPlayStateName(pStreamEx->Out.enmPlayState) )); 661 709 else 662 LogFunc(("Input stream '%s': %s -> %s\n", pStreamEx->Core.szName, 663 PDMHostAudioStreamStateGetName(enmOldState), PDMHostAudioStreamStateGetName(enmNewState) )); 710 LogFunc(("Input stream '%s': %s/%s -> %s/%s\n", pStreamEx->Core.szName, 711 PDMHostAudioStreamStateGetName(enmOldState), drvAudioCaptureStateName(enmCaptureState), 712 PDMHostAudioStreamStateGetName(enmNewState), drvAudioCaptureStateName(pStreamEx->In.enmCaptureState) )); 664 713 665 714 pStreamEx->enmLastBackendState = enmNewState; … … 1098 1147 if (pCfgReq->Backend.cFramesPreBuffering == UINT32_MAX) /* Set default pre-buffering size if nothing explicitly is set. */ 1099 1148 { 1100 /* Pre-buffer 66% of the buffer. */ 1101 pCfgReq->Backend.cFramesPreBuffering = pCfgReq->Backend.cFramesBufferSize * 2 / 3; 1149 /* Pre-buffer 66% of the buffer for output streams, but only 50% for input. Capping both at 200ms. */ 1150 if (pCfgReq->enmDir == PDMAUDIODIR_OUT) 1151 pCfgReq->Backend.cFramesPreBuffering = pCfgReq->Backend.cFramesBufferSize * 2 / 3; 1152 else 1153 pCfgReq->Backend.cFramesPreBuffering = pCfgReq->Backend.cFramesBufferSize / 2; 1154 uint32_t const cFramesMax = PDMAudioPropsMilliToFrames(&pCfgReq->Props, 200); 1155 pCfgReq->Backend.cFramesPreBuffering = RT_MIN(pCfgReq->Backend.cFramesPreBuffering, cFramesMax); 1102 1156 pszWhat = "default"; 1103 1157 } … … 1507 1561 * @param pThis Pointer to driver instance. 1508 1562 * @param pStreamEx Stream to initialize. 1509 * @param fFlags PDMAUDIOSTREAM_CREATE_F_XXX.1510 1563 * @param pCfgHost Stream configuration to use for the host side (backend). 1511 1564 * @param pCfgGuest Stream configuration to use for the guest side. 1512 1565 */ 1513 static int drvAudioStreamInitInternal(PDRVAUDIO pThis, PDRVAUDIOSTREAM pStreamEx, uint32_t fFlags,1566 static int drvAudioStreamInitInternal(PDRVAUDIO pThis, PDRVAUDIOSTREAM pStreamEx, 1514 1567 PPDMAUDIOSTREAMCFG pCfgHost, PPDMAUDIOSTREAMCFG pCfgGuest) 1515 1568 { … … 1551 1604 Assert(PDMAudioPropsAreValid(&CfgHostAcq.Props)); 1552 1605 1553 /* Set the stream properties (currently guest side, when DevSB16 is 1554 converted to mixer and PDMAUDIOSTREAM_CREATE_F_NO_MIXBUF becomes 1555 default, this will just be the stream properties). */ 1556 if (fFlags & PDMAUDIOSTREAM_CREATE_F_NO_MIXBUF) 1557 pStreamEx->Core.Props = CfgHostAcq.Props; 1558 else 1559 pStreamEx->Core.Props = pCfgGuest->Props; 1606 /* Set the stream properties. */ 1607 pStreamEx->Core.Props = CfgHostAcq.Props; 1560 1608 1561 1609 /* Let the user know if the backend changed some of the tweakable values. */ … … 1625 1673 * Configure host buffers. 1626 1674 */ 1627 1628 /* Destroy any former mixing buffer. */ 1629 AudioMixBufDestroy(&pStreamEx->Host.MixBuf); 1630 1631 if (!(fFlags & PDMAUDIOSTREAM_CREATE_F_NO_MIXBUF)) 1632 { 1633 Assert(pCfgHost->enmDir == PDMAUDIODIR_IN); 1634 rc = AudioMixBufInit(&pStreamEx->Host.MixBuf, pStreamEx->Core.szName, &CfgHostAcq.Props, CfgHostAcq.Backend.cFramesBufferSize); 1635 AssertRCReturn(rc, rc); 1636 } 1675 Assert(pStreamEx->cbPreBufThreshold == 0); 1676 if (CfgHostAcq.Backend.cFramesPreBuffering != 0) 1677 pStreamEx->cbPreBufThreshold = PDMAudioPropsFramesToBytes(&CfgHostAcq.Props, CfgHostAcq.Backend.cFramesPreBuffering); 1678 1637 1679 /* Allocate space for pre-buffering of output stream w/o mixing buffers. */ 1638 elseif (pCfgHost->enmDir == PDMAUDIODIR_OUT)1680 if (pCfgHost->enmDir == PDMAUDIODIR_OUT) 1639 1681 { 1640 1682 Assert(pStreamEx->Out.cbPreBufAlloc == 0); 1641 Assert(pStreamEx->Out.cbPreBufThreshold == 0);1642 1683 Assert(pStreamEx->Out.cbPreBuffered == 0); 1643 1684 Assert(pStreamEx->Out.offPreBuf == 0); 1644 1685 if (CfgHostAcq.Backend.cFramesPreBuffering != 0) 1645 1686 { 1646 pStreamEx->Out.cbPreBufThreshold = PDMAudioPropsFramesToBytes(&CfgHostAcq.Props, CfgHostAcq.Backend.cFramesPreBuffering);1647 1687 pStreamEx->Out.cbPreBufAlloc = PDMAudioPropsFramesToBytes(&CfgHostAcq.Props, 1648 1688 CfgHostAcq.Backend.cFramesBufferSize - 2); 1649 pStreamEx->Out.cbPreBufAlloc = RT_MIN(RT_ALIGN_32(pStreamEx-> Out.cbPreBufThreshold + _8K, _4K),1650 pStreamEx->Out.cbPreBufAlloc);1689 pStreamEx->Out.cbPreBufAlloc = RT_MIN(RT_ALIGN_32(pStreamEx->cbPreBufThreshold + _8K, _4K), 1690 pStreamEx->Out.cbPreBufAlloc); 1651 1691 pStreamEx->Out.pbPreBuf = (uint8_t *)RTMemAllocZ(pStreamEx->Out.cbPreBufAlloc); 1652 1692 AssertReturn(pStreamEx->Out.pbPreBuf, VERR_NO_MEMORY); … … 1663 1703 PDMAudioPropsMilliToBytes(&pCfgGuest->Props, pCfgGuest->Device.cMsSchedulingHint))); 1664 1704 1665 /* Destroy any former mixing buffer. */1666 AudioMixBufDestroy(&pStreamEx->Guest.MixBuf);1667 1668 if (!(fFlags & PDMAUDIOSTREAM_CREATE_F_NO_MIXBUF))1669 {1670 Assert(pCfgHost->enmDir == PDMAUDIODIR_IN);1671 rc = AudioMixBufInit(&pStreamEx->Guest.MixBuf, pStreamEx->Core.szName, &pCfgGuest->Props, CfgHostAcq.Backend.cFramesBufferSize);1672 AssertRCReturn(rc, rc);1673 }1674 1675 if (RT_FAILURE(rc))1676 LogRel(("Audio: Creating stream '%s' failed with %Rrc\n", pStreamEx->Core.szName, rc));1677 1678 if (!(fFlags & PDMAUDIOSTREAM_CREATE_F_NO_MIXBUF))1679 {1680 Assert(pCfgHost->enmDir == PDMAUDIODIR_IN);1681 /* Host (Parent) -> Guest (Child). */1682 rc = AudioMixBufLinkTo(&pStreamEx->Host.MixBuf, &pStreamEx->Guest.MixBuf);1683 AssertRC(rc);1684 }1685 1686 1705 /* 1687 1706 * Register statistics. … … 1691 1710 PDMDrvHlpSTAMRegisterF(pDrvIns, &pStreamEx->Host.Cfg.Backend.cFramesBufferSize, STAMTYPE_U32, STAMVISIBILITY_USED, STAMUNIT_NONE, 1692 1711 "Host side: The size of the backend buffer (in frames)", "%s/0-HostBackendBufSize", pStreamEx->Core.szName); 1693 if (!(fFlags & PDMAUDIOSTREAM_CREATE_F_NO_MIXBUF))1694 {1695 Assert(pCfgHost->enmDir == PDMAUDIODIR_IN);1696 PDMDrvHlpSTAMRegisterF(pDrvIns, &pStreamEx->Host.MixBuf.cFrames, STAMTYPE_U32, STAMVISIBILITY_USED, STAMUNIT_NONE,1697 "Host side: The size of the mixer buffer (in frames)", "%s/1-HostMixBufSize", pStreamEx->Core.szName);1698 PDMDrvHlpSTAMRegisterF(pDrvIns, &pStreamEx->Guest.MixBuf.cFrames, STAMTYPE_U32, STAMVISIBILITY_USED, STAMUNIT_NONE,1699 "Guest side: The size of the mixer buffer (in frames)", "%s/2-GuestMixBufSize", pStreamEx->Core.szName);1700 PDMDrvHlpSTAMRegisterF(pDrvIns, &pStreamEx->Host.MixBuf.cMixed, STAMTYPE_U32, STAMVISIBILITY_USED, STAMUNIT_NONE,1701 "Host side: Number of frames in the mixer buffer", "%s/1-HostMixBufUsed", pStreamEx->Core.szName);1702 PDMDrvHlpSTAMRegisterF(pDrvIns, &pStreamEx->Guest.MixBuf.cUsed, STAMTYPE_U32, STAMVISIBILITY_USED, STAMUNIT_NONE,1703 "Guest side: Number of frames in the mixer buffer", "%s/2-GuestMixBufUsed", pStreamEx->Core.szName);1704 }1705 1712 if (pCfgGuest->enmDir == PDMAUDIODIR_IN) 1706 1713 { … … 1761 1768 AssertReturn(pCfgHost->enmDir == pCfgGuest->enmDir, VERR_MISMATCH); 1762 1769 AssertReturn(pCfgHost->enmDir == PDMAUDIODIR_IN || pCfgHost->enmDir == PDMAUDIODIR_OUT, VERR_NOT_SUPPORTED); 1763 /* Require PDMAUDIOSTREAM_CREATE_F_NO_MIXBUF for output streams: */1764 AssertReturn((fFlags & PDMAUDIOSTREAM_CREATE_F_NO_MIXBUF) || pCfgHost->enmDir == PDMAUDIODIR_IN, VERR_INVALID_FLAGS);1765 1770 1766 1771 /* … … 1813 1818 pStreamEx->Core.enmDir = pCfgHost->enmDir; 1814 1819 pStreamEx->Core.cbBackend = (uint32_t)cbHstStrm; 1815 pStreamEx->fNoMixBufs = RT_BOOL(fFlags & PDMAUDIOSTREAM_CREATE_F_NO_MIXBUF);1816 1820 pStreamEx->fDestroyImmediate = true; 1817 1821 pStreamEx->hReqInitAsync = NIL_RTREQ; … … 1849 1853 * Try to init the rest. 1850 1854 */ 1851 rc = drvAudioStreamInitInternal(pThis, pStreamEx, fFlags,pCfgHost, pCfgGuest);1855 rc = drvAudioStreamInitInternal(pThis, pStreamEx, pCfgHost, pCfgGuest); 1852 1856 if (RT_SUCCESS(rc)) 1853 1857 { … … 1870 1874 { 1871 1875 if (pThis->CfgIn.Dbg.fEnabled) 1872 { 1873 AudioHlpFileCreateAndOpen(&pStreamEx->In.Dbg.pFileCaptureNonInterleaved, pThis->CfgIn.Dbg.szPathOut, 1874 "DrvAudioCapNonInt", pThis->pDrvIns->iInstance, &pStreamEx->Host.Cfg.Props); 1875 AudioHlpFileCreateAndOpen(&pStreamEx->In.Dbg.pFileStreamRead, pThis->CfgIn.Dbg.szPathOut, 1876 "DrvAudioRead", pThis->pDrvIns->iInstance, &pStreamEx->Host.Cfg.Props); 1877 } 1876 AudioHlpFileCreateAndOpen(&pStreamEx->In.Dbg.pFileCapture, pThis->CfgIn.Dbg.szPathOut, 1877 "DrvAudioCapture", pThis->pDrvIns->iInstance, &pStreamEx->Host.Cfg.Props); 1878 1878 } 1879 1879 else /* Out */ 1880 1880 { 1881 1881 if (pThis->CfgOut.Dbg.fEnabled) 1882 { 1883 AudioHlpFileCreateAndOpen(&pStreamEx->Out.Dbg.pFilePlayNonInterleaved, pThis->CfgOut.Dbg.szPathOut, 1884 "DrvAudioPlayNonInt", pThis->pDrvIns->iInstance, &pStreamEx->Host.Cfg.Props); 1885 AudioHlpFileCreateAndOpen(&pStreamEx->Out.Dbg.pFileStreamWrite, pThis->CfgOut.Dbg.szPathOut, 1886 "DrvAudioWrite", pThis->pDrvIns->iInstance, &pStreamEx->Host.Cfg.Props); 1887 } 1882 AudioHlpFileCreateAndOpen(&pStreamEx->Out.Dbg.pFilePlay, pThis->CfgOut.Dbg.szPathOut, 1883 "DrvAudioPlay", pThis->pDrvIns->iInstance, &pStreamEx->Host.Cfg.Props); 1888 1884 } 1889 1885 … … 2013 2009 int rc = drvAudioStreamDestroyInternalBackend(pThis, pStreamEx); 2014 2010 2015 /* Destroy mixing buffers. */2016 AudioMixBufDestroy(&pStreamEx->Guest.MixBuf);2017 AudioMixBufDestroy(&pStreamEx->Host.MixBuf);2018 2019 2011 /* Free pre-buffer space. */ 2020 2012 if ( pStreamEx->Core.enmDir == PDMAUDIODIR_OUT … … 2048 2040 if (pThis->CfgIn.Dbg.fEnabled) 2049 2041 { 2050 AudioHlpFileDestroy(pStreamEx->In.Dbg.pFileCaptureNonInterleaved); 2051 pStreamEx->In.Dbg.pFileCaptureNonInterleaved = NULL; 2052 2053 AudioHlpFileDestroy(pStreamEx->In.Dbg.pFileStreamRead); 2054 pStreamEx->In.Dbg.pFileStreamRead = NULL; 2042 AudioHlpFileDestroy(pStreamEx->In.Dbg.pFileCapture); 2043 pStreamEx->In.Dbg.pFileCapture = NULL; 2055 2044 } 2056 2045 } … … 2060 2049 if (pThis->CfgOut.Dbg.fEnabled) 2061 2050 { 2062 AudioHlpFileDestroy(pStreamEx->Out.Dbg.pFilePlayNonInterleaved); 2063 pStreamEx->Out.Dbg.pFilePlayNonInterleaved = NULL; 2064 2065 AudioHlpFileDestroy(pStreamEx->Out.Dbg.pFileStreamWrite); 2066 pStreamEx->Out.Dbg.pFileStreamWrite = NULL; 2051 AudioHlpFileDestroy(pStreamEx->Out.Dbg.pFilePlay); 2052 pStreamEx->Out.Dbg.pFilePlay = NULL; 2067 2053 } 2068 2054 } … … 2285 2271 Assert(RTCritSectIsOwner(&pStreamEx->Core.CritSect)); 2286 2272 2287 if (pStreamEx->fNoMixBufs)2288 {2289 AudioMixBufReset(&pStreamEx->Guest.MixBuf);2290 AudioMixBufReset(&pStreamEx->Host.MixBuf);2291 }2292 2293 2273 pStreamEx->nsLastIterated = 0; 2294 2274 pStreamEx->nsLastPlayedCaptured = 0; … … 2298 2278 pStreamEx->Out.cbPreBuffered = 0; 2299 2279 pStreamEx->Out.offPreBuf = 0; 2300 pStreamEx->Out.enmPlayState = pStreamEx-> Out.cbPreBufThreshold > 02280 pStreamEx->Out.enmPlayState = pStreamEx->cbPreBufThreshold > 0 2301 2281 ? DRVAUDIOPLAYSTATE_PREBUF : DRVAUDIOPLAYSTATE_PLAY; 2302 2282 } 2283 else 2284 pStreamEx->In.enmCaptureState = pStreamEx->cbPreBufThreshold > 0 2285 ? DRVAUDIOCAPTURESTATE_PREBUF : DRVAUDIOCAPTURESTATE_CAPTURING; 2303 2286 } 2304 2287 … … 2717 2700 if (RT_SUCCESS(rc)) 2718 2701 { 2719 /* Reset the playstate before we try to start. */2702 /* Reset the state before we try to start. */ 2720 2703 PDMHOSTAUDIOSTREAMSTATE const enmBackendState = drvAudioStreamGetBackendState(pThis, pStreamEx); 2721 2704 pStreamEx->enmLastBackendState = enmBackendState; 2705 pStreamEx->offInternal = 0; 2706 2722 2707 if (pStreamEx->Core.enmDir == PDMAUDIODIR_OUT) 2723 2708 { … … 2728 2713 { 2729 2714 case PDMHOSTAUDIOSTREAMSTATE_INITIALIZING: 2730 if (pStreamEx-> Out.cbPreBufThreshold > 0)2715 if (pStreamEx->cbPreBufThreshold > 0) 2731 2716 pStreamEx->Out.enmPlayState = DRVAUDIOPLAYSTATE_PREBUF; 2732 2717 break; … … 2735 2720 RT_FALL_THROUGH(); 2736 2721 case PDMHOSTAUDIOSTREAMSTATE_OKAY: 2737 pStreamEx->Out.enmPlayState = pStreamEx-> Out.cbPreBufThreshold > 02722 pStreamEx->Out.enmPlayState = pStreamEx->cbPreBufThreshold > 0 2738 2723 ? DRVAUDIOPLAYSTATE_PREBUF : DRVAUDIOPLAYSTATE_PLAY; 2739 2724 break; … … 2751 2736 } 2752 2737 else 2753 LogFunc(("ENABLE: enmBackendState=%s\n", PDMHostAudioStreamStateGetName(enmBackendState))); 2738 { 2739 pStreamEx->In.enmCaptureState = DRVAUDIOCAPTURESTATE_NO_CAPTURE; 2740 switch (enmBackendState) 2741 { 2742 case PDMHOSTAUDIOSTREAMSTATE_INITIALIZING: 2743 pStreamEx->In.enmCaptureState = DRVAUDIOCAPTURESTATE_PREBUF; 2744 break; 2745 case PDMHOSTAUDIOSTREAMSTATE_DRAINING: 2746 AssertFailed(); 2747 RT_FALL_THROUGH(); 2748 case PDMHOSTAUDIOSTREAMSTATE_OKAY: 2749 pStreamEx->In.enmCaptureState = pStreamEx->cbPreBufThreshold > 0 2750 ? DRVAUDIOCAPTURESTATE_PREBUF : DRVAUDIOCAPTURESTATE_CAPTURING; 2751 break; 2752 case PDMHOSTAUDIOSTREAMSTATE_NOT_WORKING: 2753 case PDMHOSTAUDIOSTREAMSTATE_INACTIVE: 2754 break; 2755 /* no default */ 2756 case PDMHOSTAUDIOSTREAMSTATE_INVALID: 2757 case PDMHOSTAUDIOSTREAMSTATE_END: 2758 case PDMHOSTAUDIOSTREAMSTATE_32BIT_HACK: 2759 break; 2760 } 2761 LogFunc(("ENABLE: enmBackendState=%s enmCaptureState=%s\n", PDMHostAudioStreamStateGetName(enmBackendState), 2762 drvAudioCaptureStateName(pStreamEx->In.enmCaptureState))); 2763 } 2754 2764 2755 2765 rc = drvAudioStreamControlInternalBackend(pThis, pStreamEx, PDMAUDIOSTREAMCMD_ENABLE); 2756 2766 if (RT_SUCCESS(rc)) 2757 2767 { 2768 pStreamEx->nsStarted = RTTimeNanoTS(); 2758 2769 pStreamEx->fStatus |= PDMAUDIOSTREAM_STS_ENABLED; 2759 2770 PDMAUDIOSTREAM_STS_ASSERT_VALID(pStreamEx->fStatus); … … 2992 3003 { 2993 3004 if (cbWrittenNow != cbToWrite) 2994 Log3Func(("%s: @%#RX64: Wrote lessbytes than requested: %#x, requested %#x\n",3005 Log3Func(("%s: @%#RX64: Wrote fewer bytes than requested: %#x, requested %#x\n", 2995 3006 pStreamEx->Core.szName, pStreamEx->offInternal, cbWrittenNow, cbToWrite)); 2996 3007 #ifdef DEBUG_bird … … 3037 3048 Log3Func(("[%s] Pre-buffering (%s): wrote %#x bytes => %#x bytes / %u%%\n", 3038 3049 pStreamEx->Core.szName, drvAudioPlayStateName(pStreamEx->Out.enmPlayState), cbBuf, pStreamEx->Out.cbPreBuffered, 3039 pStreamEx->Out.cbPreBuffered * 100 / RT_MAX(pStreamEx-> Out.cbPreBufThreshold, 1)));3050 pStreamEx->Out.cbPreBuffered * 100 / RT_MAX(pStreamEx->cbPreBufThreshold, 1))); 3040 3051 3041 3052 } … … 3269 3280 3270 3281 /** 3271 * @interface_method_impl{PDMIAUDIOCONNECTOR,pfnStreamGetReadable} 3272 */ 3273 static DECLCALLBACK(uint32_t) drvAudioStreamGetReadable(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream) 3274 { 3275 PDRVAUDIO pThis = RT_FROM_MEMBER(pInterface, DRVAUDIO, IAudioConnector); 3276 AssertPtr(pThis); 3282 * @interface_method_impl{PDMIAUDIOCONNECTOR,pfnStreamGetState} 3283 */ 3284 static DECLCALLBACK(PDMAUDIOSTREAMSTATE) drvAudioStreamGetState(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream) 3285 { 3286 PDRVAUDIO pThis = RT_FROM_MEMBER(pInterface, DRVAUDIO, IAudioConnector); 3277 3287 PDRVAUDIOSTREAM pStreamEx = (PDRVAUDIOSTREAM)pStream; 3278 AssertPtrReturn(pStreamEx, 0); 3279 AssertReturn(pStreamEx->Core.uMagic == PDMAUDIOSTREAM_MAGIC, 0); 3280 AssertReturn(pStreamEx->uMagic == DRVAUDIOSTREAM_MAGIC, 0); 3281 AssertMsg(pStreamEx->Core.enmDir == PDMAUDIODIR_IN, ("Can't read from a non-input stream\n")); 3282 3288 AssertPtrReturn(pStreamEx, PDMAUDIOSTREAMSTATE_INVALID); 3289 AssertReturn(pStreamEx->Core.uMagic == PDMAUDIOSTREAM_MAGIC, PDMAUDIOSTREAMSTATE_INVALID); 3290 AssertReturn(pStreamEx->uMagic == DRVAUDIOSTREAM_MAGIC, PDMAUDIOSTREAMSTATE_INVALID); 3291 3292 /* 3293 * Get the status mask. 3294 */ 3283 3295 int rc = RTCritSectEnter(&pStreamEx->Core.CritSect); 3284 AssertRCReturn(rc, 0);3296 AssertRCReturn(rc, PDMAUDIOSTREAMSTATE_INVALID); 3285 3297 RTCritSectRwEnterShared(&pThis->CritSectHotPlug); 3286 3298 3287 /* 3288 * ... 3289 */ 3290 uint32_t cbReadable = 0; 3291 3292 /* All input streams for this driver disabled? See @bugref{9882}. */ 3293 const bool fDisabled = !pThis->In.fEnabled; 3294 3295 if ( pThis->pHostDrvAudio 3296 && ( PDMAudioStrmStatusCanRead(pStreamEx->fStatus) 3297 || fDisabled) 3298 ) 3299 { 3300 PDMHOSTAUDIOSTREAMSTATE const enmBackendState = drvAudioStreamGetBackendState(pThis, pStreamEx); 3301 if (pStreamEx->fNoMixBufs) 3302 cbReadable = pThis->pHostDrvAudio 3303 && (pStreamEx->fStatus & PDMAUDIOSTREAM_STS_BACKEND_READY) 3304 && enmBackendState == PDMHOSTAUDIOSTREAMSTATE_OKAY 3305 && !fDisabled 3306 ? pThis->pHostDrvAudio->pfnStreamGetReadable(pThis->pHostDrvAudio, pStreamEx->pBackend) 3307 : 0; 3308 else 3309 { 3310 const uint32_t cfReadable = AudioMixBufLive(&pStreamEx->Guest.MixBuf); 3311 cbReadable = AUDIOMIXBUF_F2B(&pStreamEx->Guest.MixBuf, cfReadable); 3312 } 3313 if (!cbReadable) 3314 { 3315 /* 3316 * If nothing is readable, check if the stream on the backend side is ready to be read from. 3317 * If it isn't, return the number of bytes readable since the last read from this stream. 3318 * 3319 * This is needed for backends (e.g. VRDE) which do not provide any input data in certain 3320 * situations, but the device emulation needs input data to keep the DMA transfers moving. 3321 * Reading the actual data from a stream then will return silence then. 3322 */ 3323 if ( enmBackendState != PDMHOSTAUDIOSTREAMSTATE_OKAY /** @todo probably not correct. OTOH, I'm not sure if we do what the above comment claims either. */ 3324 || fDisabled) 3325 { 3326 cbReadable = PDMAudioPropsNanoToBytes(&pStreamEx->Host.Cfg.Props, 3327 RTTimeNanoTS() - pStreamEx->nsLastReadWritten); 3328 if (!(pStreamEx->Core.fWarningsShown & PDMAUDIOSTREAM_WARN_FLAGS_DISABLED)) 3329 { 3330 if (fDisabled) 3331 LogRel(("Audio: Input for driver '%s' has been disabled, returning silence\n", pThis->BackendCfg.szName)); 3332 else 3333 LogRel(("Audio: Warning: Input for stream '%s' of driver '%s' not ready (current input status is %s), returning silence\n", 3334 pStreamEx->Core.szName, pThis->BackendCfg.szName, PDMHostAudioStreamStateGetName(enmBackendState) )); 3335 3336 pStreamEx->Core.fWarningsShown |= PDMAUDIOSTREAM_WARN_FLAGS_DISABLED; 3337 } 3338 } 3339 } 3340 3341 /* Make sure to align the readable size to the guest's frame size. */ 3342 if (cbReadable) 3343 cbReadable = PDMAudioPropsFloorBytesToFrame(&pStreamEx->Guest.Cfg.Props, cbReadable); 3344 } 3299 PDMHOSTAUDIOSTREAMSTATE const enmBackendState = drvAudioStreamGetBackendStateAndProcessChanges(pThis, pStreamEx); 3300 uint32_t const fStrmStatus = pStreamEx->fStatus; 3301 PDMAUDIODIR const enmDir = pStreamEx->Guest.Cfg.enmDir; 3302 Assert(enmDir == PDMAUDIODIR_IN || enmDir == PDMAUDIODIR_OUT); 3345 3303 3346 3304 RTCritSectRwLeaveShared(&pThis->CritSectHotPlug); 3347 3305 RTCritSectLeave(&pStreamEx->Core.CritSect); 3348 Log3Func(("[%s] cbReadable=%#RX32 (%RU64ms)\n", 3349 pStreamEx->Core.szName, cbReadable, PDMAudioPropsBytesToMilli(&pStreamEx->Host.Cfg.Props, cbReadable))); 3350 return cbReadable; 3306 3307 /* 3308 * Translate it to state enum value. 3309 */ 3310 PDMAUDIOSTREAMSTATE enmState; 3311 if (!(fStrmStatus & PDMAUDIOSTREAM_STS_NEED_REINIT)) 3312 { 3313 if (fStrmStatus & PDMAUDIOSTREAM_STS_BACKEND_CREATED) 3314 { 3315 if ( (fStrmStatus & PDMAUDIOSTREAM_STS_ENABLED) 3316 && (enmDir == PDMAUDIODIR_IN ? pThis->In.fEnabled : pThis->Out.fEnabled) 3317 && ( enmBackendState == PDMHOSTAUDIOSTREAMSTATE_OKAY 3318 || enmBackendState == PDMHOSTAUDIOSTREAMSTATE_DRAINING 3319 || enmBackendState == PDMHOSTAUDIOSTREAMSTATE_INITIALIZING )) 3320 enmState = enmDir == PDMAUDIODIR_IN ? PDMAUDIOSTREAMSTATE_ENABLED_READABLE : PDMAUDIOSTREAMSTATE_ENABLED_WRITABLE; 3321 else 3322 enmState = PDMAUDIOSTREAMSTATE_INACTIVE; 3323 } 3324 else 3325 enmState = PDMAUDIOSTREAMSTATE_NOT_WORKING; 3326 } 3327 else 3328 enmState = PDMAUDIOSTREAMSTATE_NEED_REINIT; 3329 3330 #ifdef LOG_ENABLED 3331 char szStreamSts[DRVAUDIO_STATUS_STR_MAX]; 3332 #endif 3333 Log3Func(("[%s] returns %s (status: %s)\n", pStreamEx->Core.szName, PDMAudioStreamStateGetName(enmState), 3334 drvAudioStreamStatusToStr(szStreamSts, fStrmStatus))); 3335 return enmState; 3351 3336 } 3352 3337 … … 3370 3355 3371 3356 /* 3372 * ... 3373 * 3374 * Note: We don't propagate the backend stream's status to the outside -- it's the job of this 3375 * audio connector to make sense of it. 3357 * Use the playback and backend states to determin how much can be written, if anything. 3376 3358 */ 3377 3359 uint32_t cbWritable = 0; … … 3461 3443 3462 3444 /** 3463 * @interface_method_impl{PDMIAUDIOCONNECTOR,pfnStreamGetState}3464 */3465 static DECLCALLBACK(PDMAUDIOSTREAMSTATE) drvAudioStreamGetState(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream)3466 {3467 PDRVAUDIO pThis = RT_FROM_MEMBER(pInterface, DRVAUDIO, IAudioConnector);3468 PDRVAUDIOSTREAM pStreamEx = (PDRVAUDIOSTREAM)pStream;3469 AssertPtrReturn(pStreamEx, PDMAUDIOSTREAMSTATE_INVALID);3470 AssertReturn(pStreamEx->Core.uMagic == PDMAUDIOSTREAM_MAGIC, PDMAUDIOSTREAMSTATE_INVALID);3471 AssertReturn(pStreamEx->uMagic == DRVAUDIOSTREAM_MAGIC, PDMAUDIOSTREAMSTATE_INVALID);3472 3473 /*3474 * Get the status mask.3475 */3476 int rc = RTCritSectEnter(&pStreamEx->Core.CritSect);3477 AssertRCReturn(rc, PDMAUDIOSTREAMSTATE_INVALID);3478 RTCritSectRwEnterShared(&pThis->CritSectHotPlug);3479 3480 PDMHOSTAUDIOSTREAMSTATE const enmBackendState = drvAudioStreamGetBackendStateAndProcessChanges(pThis, pStreamEx);3481 uint32_t const fStrmStatus = pStreamEx->fStatus;3482 PDMAUDIODIR const enmDir = pStreamEx->Guest.Cfg.enmDir;3483 Assert(enmDir == PDMAUDIODIR_IN || enmDir == PDMAUDIODIR_OUT);3484 3485 RTCritSectRwLeaveShared(&pThis->CritSectHotPlug);3486 RTCritSectLeave(&pStreamEx->Core.CritSect);3487 3488 /*3489 * Translate it to state enum value.3490 */3491 PDMAUDIOSTREAMSTATE enmState;3492 if (!(fStrmStatus & PDMAUDIOSTREAM_STS_NEED_REINIT))3493 {3494 if (fStrmStatus & PDMAUDIOSTREAM_STS_BACKEND_CREATED)3495 {3496 if ( (fStrmStatus & PDMAUDIOSTREAM_STS_ENABLED)3497 && (enmDir == PDMAUDIODIR_IN ? pThis->In.fEnabled : pThis->Out.fEnabled)3498 && ( enmBackendState == PDMHOSTAUDIOSTREAMSTATE_OKAY3499 || enmBackendState == PDMHOSTAUDIOSTREAMSTATE_DRAINING3500 || enmBackendState == PDMHOSTAUDIOSTREAMSTATE_INITIALIZING ))3501 enmState = enmDir == PDMAUDIODIR_IN ? PDMAUDIOSTREAMSTATE_ENABLED_READABLE : PDMAUDIOSTREAMSTATE_ENABLED_WRITABLE;3502 else3503 enmState = PDMAUDIOSTREAMSTATE_INACTIVE;3504 }3505 else3506 enmState = PDMAUDIOSTREAMSTATE_NOT_WORKING;3507 }3508 else3509 enmState = PDMAUDIOSTREAMSTATE_NEED_REINIT;3510 3511 #ifdef LOG_ENABLED3512 char szStreamSts[DRVAUDIO_STATUS_STR_MAX];3513 #endif3514 Log3Func(("[%s] returns %s (status: %s)\n", pStreamEx->Core.szName, PDMAudioStreamStateGetName(enmState),3515 drvAudioStreamStatusToStr(szStreamSts, fStrmStatus)));3516 return enmState;3517 }3518 3519 3520 /**3521 * @interface_method_impl{PDMIAUDIOCONNECTOR,pfnStreamSetVolume}3522 */3523 static DECLCALLBACK(int) drvAudioStreamSetVolume(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream, PPDMAUDIOVOLUME pVol)3524 {3525 AssertPtrReturn(pInterface, VERR_INVALID_POINTER);3526 PDRVAUDIOSTREAM pStreamEx = (PDRVAUDIOSTREAM)pStream;3527 AssertPtrReturn(pStreamEx, VERR_INVALID_POINTER);3528 AssertPtrReturn(pVol, VERR_INVALID_POINTER);3529 AssertReturn(pStreamEx->Core.uMagic == PDMAUDIOSTREAM_MAGIC, VERR_INVALID_MAGIC);3530 AssertReturn(pStreamEx->uMagic == DRVAUDIOSTREAM_MAGIC, VERR_INVALID_MAGIC);3531 AssertReturn(!pStreamEx->fNoMixBufs, VWRN_INVALID_STATE);3532 3533 LogFlowFunc(("[%s] volL=%RU32, volR=%RU32, fMute=%RTbool\n", pStreamEx->Core.szName, pVol->uLeft, pVol->uRight, pVol->fMuted));3534 3535 int rc = RTCritSectEnter(&pStreamEx->Core.CritSect);3536 AssertRCReturn(rc, rc);3537 3538 AudioMixBufSetVolume(&pStreamEx->Guest.MixBuf, pVol);3539 AudioMixBufSetVolume(&pStreamEx->Host.MixBuf, pVol);3540 3541 RTCritSectLeave(&pStreamEx->Core.CritSect);3542 return VINF_SUCCESS;3543 }3544 3545 3546 /**3547 3445 * @interface_method_impl{PDMIAUDIOCONNECTOR,pfnStreamPlay} 3548 3446 */ … … 3562 3460 AssertReturn(cbBuf, VERR_INVALID_PARAMETER); 3563 3461 uint32_t uTmp; 3564 if (!pcbWritten) 3462 if (pcbWritten) 3463 AssertPtrReturn(pcbWritten, VERR_INVALID_PARAMETER); 3464 else 3565 3465 pcbWritten = &uTmp; 3566 AssertPtrReturn(pcbWritten, VERR_INVALID_PARAMETER);3567 3466 3568 3467 AssertReturn(pStreamEx->Core.uMagic == PDMAUDIOSTREAM_MAGIC, VERR_INVALID_MAGIC); … … 3571 3470 ("Stream '%s' is not an output stream and therefore cannot be written to (direction is '%s')\n", 3572 3471 pStreamEx->Core.szName, PDMAudioDirGetName(pStreamEx->Core.enmDir)), VERR_ACCESS_DENIED); 3573 Assert(pStreamEx->fNoMixBufs);3574 3472 3575 3473 AssertMsg(PDMAudioPropsIsSizeAligned(&pStreamEx->Guest.Cfg.Props, cbBuf), … … 3609 3507 Assert(enmBackendState == PDMHOSTAUDIOSTREAMSTATE_OKAY); 3610 3508 rc = drvAudioStreamPlayLocked(pThis, pStreamEx, (uint8_t const *)pvBuf, cbBuf, pcbWritten); 3611 drvAudioStreamPreBuffer(pStreamEx, (uint8_t const *)pvBuf, *pcbWritten, pStreamEx-> Out.cbPreBufThreshold);3509 drvAudioStreamPreBuffer(pStreamEx, (uint8_t const *)pvBuf, *pcbWritten, pStreamEx->cbPreBufThreshold); 3612 3510 break; 3613 3511 3614 3512 case DRVAUDIOPLAYSTATE_PREBUF: 3615 if (cbBuf + pStreamEx->Out.cbPreBuffered < pStreamEx-> Out.cbPreBufThreshold)3616 rc = drvAudioStreamPlayToPreBuffer(pStreamEx, pvBuf, cbBuf, pStreamEx-> Out.cbPreBufThreshold, pcbWritten);3513 if (cbBuf + pStreamEx->Out.cbPreBuffered < pStreamEx->cbPreBufThreshold) 3514 rc = drvAudioStreamPlayToPreBuffer(pStreamEx, pvBuf, cbBuf, pStreamEx->cbPreBufThreshold, pcbWritten); 3617 3515 else if ( enmBackendState == PDMHOSTAUDIOSTREAMSTATE_OKAY 3618 3516 && (pStreamEx->fStatus & PDMAUDIOSTREAM_STS_BACKEND_READY)) … … 3620 3518 Log3Func(("[%s] Pre-buffering completing: cbBuf=%#x cbPreBuffered=%#x => %#x vs cbPreBufThreshold=%#x\n", 3621 3519 pStreamEx->Core.szName, cbBuf, pStreamEx->Out.cbPreBuffered, 3622 cbBuf + pStreamEx->Out.cbPreBuffered, pStreamEx-> Out.cbPreBufThreshold));3520 cbBuf + pStreamEx->Out.cbPreBuffered, pStreamEx->cbPreBufThreshold)); 3623 3521 rc = drvAudioStreamPreBufComitting(pThis, pStreamEx, (uint8_t const *)pvBuf, cbBuf, pcbWritten); 3624 3522 } … … 3627 3525 Log3Func(("[%s] Pre-buffering completing but device not ready: cbBuf=%#x cbPreBuffered=%#x => %#x vs cbPreBufThreshold=%#x; PREBUF -> PREBUF_OVERDUE\n", 3628 3526 pStreamEx->Core.szName, cbBuf, pStreamEx->Out.cbPreBuffered, 3629 cbBuf + pStreamEx->Out.cbPreBuffered, pStreamEx-> Out.cbPreBufThreshold));3527 cbBuf + pStreamEx->Out.cbPreBuffered, pStreamEx->cbPreBufThreshold)); 3630 3528 pStreamEx->Out.enmPlayState = DRVAUDIOPLAYSTATE_PREBUF_OVERDUE; 3631 rc = drvAudioStreamPlayToPreBuffer(pStreamEx, pvBuf, cbBuf, pStreamEx-> Out.cbPreBufThreshold, pcbWritten);3529 rc = drvAudioStreamPlayToPreBuffer(pStreamEx, pvBuf, cbBuf, pStreamEx->cbPreBufThreshold, pcbWritten); 3632 3530 } 3633 3531 break; … … 3638 3536 RT_FALL_THRU(); 3639 3537 case DRVAUDIOPLAYSTATE_PREBUF_SWITCHING: 3640 rc = drvAudioStreamPlayToPreBuffer(pStreamEx, pvBuf, cbBuf, pStreamEx-> Out.cbPreBufThreshold, pcbWritten);3538 rc = drvAudioStreamPlayToPreBuffer(pStreamEx, pvBuf, cbBuf, pStreamEx->cbPreBufThreshold, pcbWritten); 3641 3539 break; 3642 3540 … … 3662 3560 { /* likely */ } 3663 3561 else 3664 AudioHlpFileWrite(pStreamEx->Out.Dbg.pFilePlay NonInterleaved, pvBuf, *pcbWritten, 0 /* fFlags */);3562 AudioHlpFileWrite(pStreamEx->Out.Dbg.pFilePlay, pvBuf, *pcbWritten, 0 /* fFlags */); 3665 3563 } 3666 3564 else … … 3681 3579 3682 3580 3581 /** 3582 * @interface_method_impl{PDMIAUDIOCONNECTOR,pfnStreamGetReadable} 3583 */ 3584 static DECLCALLBACK(uint32_t) drvAudioStreamGetReadable(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream) 3585 { 3586 PDRVAUDIO pThis = RT_FROM_MEMBER(pInterface, DRVAUDIO, IAudioConnector); 3587 AssertPtr(pThis); 3588 PDRVAUDIOSTREAM pStreamEx = (PDRVAUDIOSTREAM)pStream; 3589 AssertPtrReturn(pStreamEx, 0); 3590 AssertReturn(pStreamEx->Core.uMagic == PDMAUDIOSTREAM_MAGIC, 0); 3591 AssertReturn(pStreamEx->uMagic == DRVAUDIOSTREAM_MAGIC, 0); 3592 AssertMsg(pStreamEx->Core.enmDir == PDMAUDIODIR_IN, ("Can't read from a non-input stream\n")); 3593 3594 3595 int rc = RTCritSectEnter(&pStreamEx->Core.CritSect); 3596 AssertRCReturn(rc, 0); 3597 RTCritSectRwEnterShared(&pThis->CritSectHotPlug); 3598 3599 /* 3600 * Use the capture state to determin how much can be written, if anything. 3601 */ 3602 uint32_t cbReadable = 0; 3603 DRVAUDIOCAPTURESTATE const enmCaptureState = pStreamEx->In.enmCaptureState; 3604 PDMHOSTAUDIOSTREAMSTATE const enmBackendState = drvAudioStreamGetBackendState(pThis, pStreamEx); RT_NOREF(enmBackendState); 3605 if ( PDMAudioStrmStatusCanRead(pStreamEx->fStatus) 3606 && pThis->pHostDrvAudio != NULL) 3607 { 3608 switch (enmCaptureState) 3609 { 3610 /* 3611 * Whatever the backend has to offer when in capture mode. 3612 */ 3613 case DRVAUDIOCAPTURESTATE_CAPTURING: 3614 Assert(pStreamEx->fStatus & PDMAUDIOSTREAM_STS_BACKEND_READY); 3615 Assert(enmBackendState == PDMHOSTAUDIOSTREAMSTATE_OKAY /* potential unplug race */); 3616 cbReadable = pThis->pHostDrvAudio->pfnStreamGetReadable(pThis->pHostDrvAudio, pStreamEx->pBackend); 3617 break; 3618 3619 /* 3620 * Same calculation as in drvAudioStreamCaptureSilence, only we cap it 3621 * at the pre-buffering threshold so we don't get into trouble when we 3622 * switch to capture mode between now and pfnStreamCapture. 3623 */ 3624 case DRVAUDIOCAPTURESTATE_PREBUF: 3625 { 3626 uint64_t const cNsStream = RTTimeNanoTS() - pStreamEx->nsStarted; 3627 uint64_t const offCur = PDMAudioPropsNanoToBytes64(&pStreamEx->Guest.Cfg.Props, cNsStream); 3628 if (offCur > pStreamEx->offInternal) 3629 { 3630 uint64_t const cbUnread = offCur - pStreamEx->offInternal; 3631 cbReadable = (uint32_t)RT_MIN(pStreamEx->cbPreBufThreshold, cbUnread); 3632 } 3633 break; 3634 } 3635 3636 case DRVAUDIOCAPTURESTATE_NO_CAPTURE: 3637 break; 3638 3639 case DRVAUDIOCAPTURESTATE_INVALID: 3640 case DRVAUDIOCAPTURESTATE_END: 3641 AssertFailed(); 3642 break; 3643 } 3644 3645 /* Make sure to align the readable size to the host's frame size. */ 3646 cbReadable = PDMAudioPropsFloorBytesToFrame(&pStreamEx->Host.Cfg.Props, cbReadable); 3647 } 3648 3649 RTCritSectRwLeaveShared(&pThis->CritSectHotPlug); 3650 RTCritSectLeave(&pStreamEx->Core.CritSect); 3651 Log3Func(("[%s] cbReadable=%#RX32 (%RU64ms) enmCaptureMode=%s enmBackendState=%s\n", 3652 pStreamEx->Core.szName, cbReadable, PDMAudioPropsBytesToMilli(&pStreamEx->Host.Cfg.Props, cbReadable), 3653 drvAudioCaptureStateName(enmCaptureState), PDMHostAudioStreamStateGetName(enmBackendState) )); 3654 return cbReadable; 3655 } 3656 3657 3658 /** 3659 * Worker for drvAudioStreamCapture that returns silence. 3660 * 3661 * The amount of silence returned is a function of how long the stream has been 3662 * enabled. 3663 * 3664 * @returns VINF_SUCCESS 3665 * @param pStreamEx The stream to commit the pre-buffering for. 3666 * @param pbBuf The output buffer. 3667 * @param cbBuf The size of the output buffer. 3668 * @param pcbRead Where to return the number of bytes actually read. 3669 */ 3670 static int drvAudioStreamCaptureSilence(PDRVAUDIOSTREAM pStreamEx, uint8_t *pbBuf, uint32_t cbBuf, uint32_t *pcbRead) 3671 { 3672 /** @todo Does not take paused time into account... */ 3673 uint64_t const cNsStream = RTTimeNanoTS() - pStreamEx->nsStarted; 3674 uint64_t const offCur = PDMAudioPropsNanoToBytes64(&pStreamEx->Guest.Cfg.Props, cNsStream); 3675 if (offCur > pStreamEx->offInternal) 3676 { 3677 uint64_t const cbUnread = offCur - pStreamEx->offInternal; 3678 uint32_t const cbToClear = (uint32_t)RT_MIN(cbBuf, cbUnread); 3679 *pcbRead = cbToClear; 3680 pStreamEx->offInternal += cbToClear; 3681 cbBuf -= cbToClear; 3682 PDMAudioPropsClearBuffer(&pStreamEx->Guest.Cfg.Props, pbBuf, cbToClear, 3683 PDMAudioPropsBytesToFrames(&pStreamEx->Guest.Cfg.Props, cbToClear)); 3684 } 3685 else 3686 *pcbRead = 0; 3687 Log4Func(("%s: @%#RX64: Read %#x bytes of silence (%#x bytes left)\n", 3688 pStreamEx->Core.szName, pStreamEx->offInternal, *pcbRead, cbBuf)); 3689 return VINF_SUCCESS; 3690 } 3691 3692 3693 /** 3694 * Worker for drvAudioStreamCapture. 3695 */ 3696 static int drvAudioStreamCaptureLocked(PDRVAUDIO pThis, PDRVAUDIOSTREAM pStreamEx, 3697 uint8_t *pbBuf, uint32_t cbBuf, uint32_t *pcbRead) 3698 { 3699 Log4Func(("%s: @%#RX64: cbBuf=%#x\n", pStreamEx->Core.szName, pStreamEx->offInternal, cbBuf)); 3700 3701 uint32_t cbReadable = pThis->pHostDrvAudio->pfnStreamGetReadable(pThis->pHostDrvAudio, pStreamEx->pBackend); 3702 pStreamEx->In.Stats.cbBackendReadableBefore = cbReadable; 3703 3704 uint32_t cbRead = 0; 3705 int rc = VINF_SUCCESS; 3706 uint8_t const cbFrame = PDMAudioPropsFrameSize(&pStreamEx->Core.Props); 3707 while (cbBuf >= cbFrame && cbReadable >= cbFrame) 3708 { 3709 uint32_t const cbToRead = PDMAudioPropsFloorBytesToFrame(&pStreamEx->Core.Props, RT_MIN(cbBuf, cbReadable)); 3710 uint32_t cbReadNow = 0; 3711 rc = pThis->pHostDrvAudio->pfnStreamCapture(pThis->pHostDrvAudio, pStreamEx->pBackend, pbBuf, cbToRead, &cbReadNow); 3712 if (RT_SUCCESS(rc)) 3713 { 3714 if (cbReadNow != cbToRead) 3715 Log4Func(("%s: @%#RX64: Read fewer bytes than requested: %#x, requested %#x\n", 3716 pStreamEx->Core.szName, pStreamEx->offInternal, cbReadNow, cbToRead)); 3717 #ifdef DEBUG_bird 3718 Assert(cbReadNow == cbToRead); 3719 #endif 3720 AssertStmt(cbReadNow <= cbToRead, cbReadNow = cbToRead); 3721 cbRead += cbReadNow; 3722 cbBuf -= cbReadNow; 3723 pbBuf += cbReadNow; 3724 pStreamEx->offInternal += cbReadNow; 3725 } 3726 else 3727 { 3728 *pcbRead = cbRead; 3729 LogFunc(("%s: @%#RX64: pfnStreamCapture failed read %#x bytes (%#x previous read, %#x readable): %Rrc\n", 3730 pStreamEx->Core.szName, pStreamEx->offInternal, cbToRead, cbRead, cbReadable, rc)); 3731 return cbRead ? VINF_SUCCESS : rc; 3732 } 3733 3734 cbReadable = pThis->pHostDrvAudio->pfnStreamGetReadable(pThis->pHostDrvAudio, pStreamEx->pBackend); 3735 } 3736 3737 *pcbRead = cbRead; 3738 pStreamEx->In.Stats.cbBackendReadableAfter = cbReadable; 3739 if (cbRead) 3740 pStreamEx->nsLastPlayedCaptured = RTTimeNanoTS(); 3741 3742 Log4Func(("%s: @%#RX64: Read %#x bytes (%#x bytes left)\n", pStreamEx->Core.szName, pStreamEx->offInternal, cbRead, cbBuf)); 3743 return rc; 3744 } 3745 3746 3747 /** 3748 * @interface_method_impl{PDMIAUDIOCONNECTOR,pfnStreamCapture} 3749 */ 3750 static DECLCALLBACK(int) drvAudioStreamCapture(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream, 3751 void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead) 3752 { 3753 PDRVAUDIO pThis = RT_FROM_MEMBER(pInterface, DRVAUDIO, IAudioConnector); 3754 AssertPtr(pThis); 3755 3756 /* 3757 * Check input and sanity. 3758 */ 3759 AssertPtrReturn(pInterface, VERR_INVALID_POINTER); 3760 PDRVAUDIOSTREAM pStreamEx = (PDRVAUDIOSTREAM)pStream; 3761 AssertPtrReturn(pStreamEx, VERR_INVALID_POINTER); 3762 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER); 3763 AssertReturn(cbBuf, VERR_INVALID_PARAMETER); 3764 uint32_t uTmp; 3765 if (pcbRead) 3766 AssertPtrReturn(pcbRead, VERR_INVALID_PARAMETER); 3767 else 3768 pcbRead = &uTmp; 3769 3770 AssertReturn(pStreamEx->Core.uMagic == PDMAUDIOSTREAM_MAGIC, VERR_INVALID_MAGIC); 3771 AssertReturn(pStreamEx->uMagic == DRVAUDIOSTREAM_MAGIC, VERR_INVALID_MAGIC); 3772 AssertMsgReturn(pStreamEx->Core.enmDir == PDMAUDIODIR_IN, 3773 ("Stream '%s' is not an input stream and therefore cannot be read from (direction is '%s')\n", 3774 pStreamEx->Core.szName, PDMAudioDirGetName(pStreamEx->Core.enmDir)), VERR_ACCESS_DENIED); 3775 3776 AssertMsg(PDMAudioPropsIsSizeAligned(&pStreamEx->Guest.Cfg.Props, cbBuf), 3777 ("Stream '%s' got a non-frame-aligned write (%#RX32 bytes)\n", pStreamEx->Core.szName, cbBuf)); 3778 3779 int rc = RTCritSectEnter(&pStreamEx->Core.CritSect); 3780 AssertRCReturn(rc, rc); 3781 3782 /* 3783 * First check that we can read from the stream, and if not, 3784 * whether to just drop the input into the bit bucket. 3785 */ 3786 if (PDMAudioStrmStatusIsReady(pStreamEx->fStatus)) 3787 { 3788 RTCritSectRwEnterShared(&pThis->CritSectHotPlug); 3789 if ( pThis->In.fEnabled /* (see @bugref{9882}) */ 3790 && pThis->pHostDrvAudio != NULL) 3791 { 3792 /* 3793 * Get the backend state and process changes to it since last time we checked. 3794 */ 3795 PDMHOSTAUDIOSTREAMSTATE const enmBackendState = drvAudioStreamGetBackendStateAndProcessChanges(pThis, pStreamEx); 3796 3797 /* 3798 * Do the transfering. 3799 */ 3800 switch (pStreamEx->In.enmCaptureState) 3801 { 3802 case DRVAUDIOCAPTURESTATE_CAPTURING: 3803 Assert(pStreamEx->fStatus & PDMAUDIOSTREAM_STS_BACKEND_READY); 3804 Assert(enmBackendState == PDMHOSTAUDIOSTREAMSTATE_OKAY); 3805 rc = drvAudioStreamCaptureLocked(pThis, pStreamEx, (uint8_t *)pvBuf, cbBuf, pcbRead); 3806 break; 3807 3808 case DRVAUDIOCAPTURESTATE_PREBUF: 3809 if (enmBackendState == PDMHOSTAUDIOSTREAMSTATE_OKAY) 3810 { 3811 uint32_t const cbReadable = pThis->pHostDrvAudio->pfnStreamGetReadable(pThis->pHostDrvAudio, 3812 pStreamEx->pBackend); 3813 if (cbReadable >= pStreamEx->cbPreBufThreshold) 3814 { 3815 Log4Func(("[%s] Pre-buffering completed: cbReadable=%#x vs cbPreBufThreshold=%#x (cbBuf=%#x)\n", 3816 pStreamEx->Core.szName, cbReadable, pStreamEx->cbPreBufThreshold, cbBuf)); 3817 pStreamEx->In.enmCaptureState = DRVAUDIOCAPTURESTATE_CAPTURING; 3818 rc = drvAudioStreamCaptureLocked(pThis, pStreamEx, (uint8_t *)pvBuf, cbBuf, pcbRead); 3819 break; 3820 } 3821 pStreamEx->In.Stats.cbBackendReadableBefore = cbReadable; 3822 pStreamEx->In.Stats.cbBackendReadableAfter = cbReadable; 3823 Log4Func(("[%s] Pre-buffering: Got %#x out of %#x\n", 3824 pStreamEx->Core.szName, cbReadable, pStreamEx->cbPreBufThreshold)); 3825 } 3826 else 3827 Log4Func(("[%s] Pre-buffering: Backend status %s\n", 3828 pStreamEx->Core.szName, PDMHostAudioStreamStateGetName(enmBackendState) )); 3829 drvAudioStreamCaptureSilence(pStreamEx, (uint8_t *)pvBuf, cbBuf, pcbRead); 3830 break; 3831 3832 case DRVAUDIOCAPTURESTATE_NO_CAPTURE: 3833 *pcbRead = 0; 3834 Log4Func(("[%s] Not capturing - backend state: %s\n", 3835 pStreamEx->Core.szName, PDMHostAudioStreamStateGetName(enmBackendState) )); 3836 break; 3837 3838 default: 3839 *pcbRead = 0; 3840 AssertMsgFailedBreak(("%d; cbBuf=%#x\n", pStreamEx->In.enmCaptureState, cbBuf)); 3841 } 3842 3843 if (!pThis->CfgIn.Dbg.fEnabled || RT_FAILURE(rc)) 3844 { /* likely */ } 3845 else 3846 AudioHlpFileWrite(pStreamEx->In.Dbg.pFileCapture, pvBuf, *pcbRead, 0 /* fFlags */); 3847 } 3848 else 3849 { 3850 *pcbRead = 0; 3851 Log4Func(("[%s] Backend stream %s, returning no data\n", pStreamEx->Core.szName, 3852 !pThis->Out.fEnabled ? "disabled" : !pThis->pHostDrvAudio ? "not attached" : "not ready yet")); 3853 } 3854 RTCritSectRwLeaveShared(&pThis->CritSectHotPlug); 3855 } 3856 else 3857 rc = VERR_AUDIO_STREAM_NOT_READY; 3858 3859 RTCritSectLeave(&pStreamEx->Core.CritSect); 3860 return rc; 3861 } 3862 3863 3864 #ifdef OLD_CAPTURE_CODE 3683 3865 /** 3684 3866 * @interface_method_impl{PDMIAUDIOCONNECTOR,pfnStreamRead} … … 3859 4041 3860 4042 if (pThis->CfgIn.Dbg.fEnabled) 3861 AudioHlpFileWrite(pStreamEx->In.Dbg.pFileCapture NonInterleaved, abChunk, cbCaptured, 0 /* fFlags */);4043 AudioHlpFileWrite(pStreamEx->In.Dbg.pFileCapture, abChunk, cbCaptured, 0 /* fFlags */); 3862 4044 3863 4045 uint32_t cfHstMixed = 0; … … 4047 4229 return rc; 4048 4230 } 4231 #endif 4049 4232 4050 4233 … … 4268 4451 if (pStreamEx->Core.enmDir == PDMAUDIODIR_OUT) 4269 4452 { 4270 if (pStreamEx-> Out.cbPreBufThreshold > 0)4453 if (pStreamEx->cbPreBufThreshold > 0) 4271 4454 { 4272 4455 DRVAUDIOPLAYSTATE const enmPlayState = pStreamEx->Out.enmPlayState; … … 5070 5253 pThis->IAudioConnector.pfnStreamControl = drvAudioStreamControl; 5071 5254 pThis->IAudioConnector.pfnStreamIterate = drvAudioStreamIterate; 5255 pThis->IAudioConnector.pfnStreamGetState = drvAudioStreamGetState; 5256 pThis->IAudioConnector.pfnStreamGetWritable = drvAudioStreamGetWritable; 5257 pThis->IAudioConnector.pfnStreamPlay = drvAudioStreamPlay; 5072 5258 pThis->IAudioConnector.pfnStreamGetReadable = drvAudioStreamGetReadable; 5073 pThis->IAudioConnector.pfnStreamGetWritable = drvAudioStreamGetWritable;5074 pThis->IAudioConnector.pfnStreamGetState = drvAudioStreamGetState;5075 pThis->IAudioConnector.pfnStreamSetVolume = drvAudioStreamSetVolume;5076 pThis->IAudioConnector.pfnStreamPlay = drvAudioStreamPlay;5077 pThis->IAudioConnector.pfnStreamRead = drvAudioStreamRead;5078 5259 pThis->IAudioConnector.pfnStreamCapture = drvAudioStreamCapture; 5079 5260 /* IHostAudioPort */
Note:
See TracChangeset
for help on using the changeset viewer.