Changeset 88760 in vbox
- Timestamp:
- Apr 29, 2021 12:54:45 AM (4 years ago)
- svn:sync-xref-src-repo-rev:
- 144090
- Location:
- trunk
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/include/VBox/vmm/pdmaudioifs.h
r88731 r88760 903 903 * @{ */ 904 904 /** No flags being set. */ 905 #define PDMAUDIOSTREAM_STS_NONE UINT32_C(0)905 #define PDMAUDIOSTREAM_STS_NONE UINT32_C(0) 906 906 /** Set if the backend for the stream has been initialized. 907 * This is generally always set after stream creation, but can be cleared if the 908 * re-initialization of the stream fails later on. */ 909 #define PDMAUDIOSTREAM_STS_INITIALIZED RT_BIT_32(0) 907 * 908 * PDMIAUDIOCONNECTOR: This is generally always set after stream creation, but 909 * can be cleared if the re-initialization of the stream fails later on. 910 * 911 * PDMIHOSTAUDIO: This may not be set immediately if the backend is doing some 912 * of the stream creation asynchronously. The DrvAudio code will not report 913 * this to the devices, but keep on prebuffering till it is set. */ 914 #define PDMAUDIOSTREAM_STS_INITIALIZED RT_BIT_32(0) 910 915 /** Set if the stream is enabled, clear if disabled. */ 911 #define PDMAUDIOSTREAM_STS_ENABLED RT_BIT_32(1)916 #define PDMAUDIOSTREAM_STS_ENABLED RT_BIT_32(1) 912 917 /** Set if the stream is paused. 913 918 * Requires enabled status to be set when used. */ 914 #define PDMAUDIOSTREAM_STS_PAUSED RT_BIT_32(2)919 #define PDMAUDIOSTREAM_STS_PAUSED RT_BIT_32(2) 915 920 /** Output only: Set when the stream is draining. 916 * Requires the enabled status to be set when used. */ 917 #define PDMAUDIOSTREAM_STS_PENDING_DISABLE RT_BIT_32(3) 918 /** Set if the stream needs to be re-initialized by the device (i.e. call 919 * PDMIAUDIOCONNECTOR::pfnStreamReInit). 920 * (The other status bits are preserved and are worked as normal while in this 921 * state, so that the stream can resume operation where it left off.) 922 * @note This is not appropriate for PDMIHOSTAUDIO::pfnStreamGetStatus. */ 923 #define PDMAUDIOSTREAM_STS_NEED_REINIT RT_BIT_32(4) 924 /** Validation mask. */ 925 #define PDMAUDIOSTREAM_STS_VALID_MASK UINT32_C(0x0000001f) 926 /** Asserts the validity of the given stream status mask. */ 921 * Requires the enabled status to be set when used. 922 * @todo See todo in drvAudioStreamPlay() regarding the suitability of this 923 * for PDMIHOSTAUDIO. */ 924 #define PDMAUDIOSTREAM_STS_PENDING_DISABLE RT_BIT_32(3) 925 926 /** PDMIAUDIOCONNECTOR: Set if the stream needs to be re-initialized by the 927 * device (i.e. call PDMIAUDIOCONNECTOR::pfnStreamReInit). (The other status 928 * bits are preserved and are worked as normal while in this state, so that the 929 * stream can resume operation where it left off.) */ 930 #define PDMAUDIOSTREAM_STS_NEED_REINIT RT_BIT_32(8) 931 /** Validation mask for PDMIAUDIOCONNECTOR. */ 932 #define PDMAUDIOSTREAM_STS_VALID_MASK UINT32_C(0x0000010f) 933 /** Asserts the validity of the given stream status mask for PDMIAUDIOCONNECTOR. */ 927 934 #define PDMAUDIOSTREAM_STS_ASSERT_VALID(a_fStreamStatus) do { \ 928 935 AssertMsg(!((a_fStreamStatus) & ~PDMAUDIOSTREAM_STS_VALID_MASK), ("%#x\n", (a_fStreamStatus))); \ 936 Assert(!((a_fStreamStatus) & PDMAUDIOSTREAM_STS_PAUSED) || ((a_fStreamStatus) & PDMAUDIOSTREAM_STS_ENABLED)); \ 937 Assert(!((a_fStreamStatus) & PDMAUDIOSTREAM_STS_PENDING_DISABLE) || ((a_fStreamStatus) & PDMAUDIOSTREAM_STS_ENABLED)); \ 938 } while (0) 939 940 /** PDMIHOSTAUDIO: Backend is preparing a device switch, DrvAudio should 941 * pre-buffer to make that smoother and quicker. 942 * Call PDMIAUDIONOTIFYFROMHOST::pfnStreamNotifyDeviceChanged when clearing. */ 943 #define PDMAUDIOSTREAM_STS_PREPARING_SWITCH RT_BIT_32(16) 944 /** Validation mask for PDMIHOSTAUDIO. */ 945 #define PDMAUDIOSTREAM_STS_VALID_MASK_BACKEND UINT32_C(0x0001000f) 946 /** Asserts the validity of the given stream status mask for PDMIHOSTAUDIO. */ 947 #define PDMAUDIOSTREAM_STS_ASSERT_VALID_BACKEND(a_fStreamStatus) do { \ 948 AssertMsg(!((a_fStreamStatus) & ~PDMAUDIOSTREAM_STS_VALID_MASK_BACKEND), ("%#x\n", (a_fStreamStatus))); \ 929 949 Assert(!((a_fStreamStatus) & PDMAUDIOSTREAM_STS_PAUSED) || ((a_fStreamStatus) & PDMAUDIOSTREAM_STS_ENABLED)); \ 930 950 Assert(!((a_fStreamStatus) & PDMAUDIOSTREAM_STS_PENDING_DISABLE) || ((a_fStreamStatus) & PDMAUDIOSTREAM_STS_ENABLED)); \ … … 979 999 * Only can be destroyed when the reference count reaches 0. */ 980 1000 uint32_t volatile cRefs; 981 /** Stream status flag. */982 uint32_t fStatus;1001 /** Stream status - PDMAUDIOSTREAM_STS_XXX. */ 1002 uint32_t fStatus; 983 1003 /** Audio direction of this stream. */ 984 1004 PDMAUDIODIR enmDir; … … 1325 1345 1326 1346 /** 1347 * Called from PDMIAUDIONOTIFYFROMHOST::pfnNotifyDeviceChanged so the backend 1348 * can start the device change for a stream. 1349 * 1350 * This is mainly to avoid the need for a list of streams in the backend. 1351 * 1352 * @param pInterface Pointer to this interface. 1353 * @param pStream Pointer to audio stream. 1354 * @param pvUser Backend specific parameter from the call to 1355 * PDMIAUDIONOTIFYFROMHOST::pfnNotifyDeviceChanged. 1356 */ 1357 DECLR3CALLBACKMEMBER(void, pfnStreamNotifyDeviceChanged,(PPDMIHOSTAUDIO pInterface, 1358 PPDMAUDIOBACKENDSTREAM pStream, void *pvUser)); 1359 1360 /** 1327 1361 * Controls an audio stream. 1328 1362 * … … 1415 1449 1416 1450 /** PDMIHOSTAUDIO interface ID. */ 1417 #define PDMIHOSTAUDIO_IID " 109d8c74-dfed-4056-b5ad-022de4d249c2"1451 #define PDMIHOSTAUDIO_IID "faab0061-c3c8-481e-b875-abbe81baf94a" 1418 1452 1419 1453 … … 1429 1463 { 1430 1464 /** 1465 * The device for the given direction changed. 1466 * 1467 * The driver above backend (DrvAudio) will call the backend back 1468 * (PDMIHOSTAUDIO::pfnStreamNotifyDeviceChanged) for all open streams in the 1469 * given direction. (This ASSUMES the backend uses one output device and one 1470 * input devices for all streams.) 1471 * 1472 * @param pInterface Pointer to this interface. 1473 * @param enmDir The audio direction. 1474 * @param pvUser Backend specific parameter for 1475 * PDMIHOSTAUDIO::pfnStreamNotifyDeviceChanged. 1476 */ 1477 DECLR3CALLBACKMEMBER(void, pfnNotifyDeviceChanged,(PPDMIAUDIONOTIFYFROMHOST pInterface, PDMAUDIODIR enmDir, void *pvUser)); 1478 1479 /** 1480 * The stream has changed its device and left the 1481 * PDMAUDIOSTREAM_STS_PREPARING_SWITCH state. 1482 * 1483 * @param pInterface Pointer to this interface. 1484 * @param pStream The stream that changed device (backend variant). 1485 * @param fReInit Set if a re-init is required, clear if not. 1486 */ 1487 DECLR3CALLBACKMEMBER(void, pfnStreamNotifyDeviceChanged,(PPDMIAUDIONOTIFYFROMHOST pInterface, 1488 PPDMAUDIOBACKENDSTREAM pStream, bool fReInit)); 1489 1490 /** 1431 1491 * One or more audio devices have changed in some way. 1432 1492 * 1433 1493 * The upstream driver/device should re-evaluate the devices they're using. 1434 1494 * 1435 * @param pInterface Pointer to this interface. 1495 * @todo r=bird: The upstream driver/device does not know which host audio 1496 * devices they are using. This is mainly for triggering enumeration and 1497 * logging of the audio devices. 1498 * 1499 * @param pInterface Pointer to this interface. 1436 1500 */ 1437 1501 DECLR3CALLBACKMEMBER(void, pfnNotifyDevicesChanged,(PPDMIAUDIONOTIFYFROMHOST pInterface)); … … 1439 1503 1440 1504 /** PDMIAUDIONOTIFYFROMHOST interface ID. */ 1441 #define PDMIAUDIONOTIFYFROMHOST_IID " ec10f36b-ec2d-4b97-9044-2a59fba837ad"1505 #define PDMIAUDIONOTIFYFROMHOST_IID "603f9d72-4b8b-4e0a-aa00-a76982931039" 1442 1506 1443 1507 /** @} */ -
trunk/include/VBox/vmm/pdmaudioinline.h
r88731 r88760 423 423 * @returns @c true if ready to be read from, @c false if not. 424 424 * @param fStatus Stream status to evaluate, PDMAUDIOSTREAM_STS_XXX. 425 * @note Not for backend statuses (use PDMAudioStrmStatusBackendCanRead)! 425 426 */ 426 427 DECLINLINE(bool) PDMAudioStrmStatusCanRead(uint32_t fStatus) … … 428 429 PDMAUDIOSTREAM_STS_ASSERT_VALID(fStatus); 429 430 AssertReturn(!(fStatus & ~PDMAUDIOSTREAM_STS_VALID_MASK), false); 431 return (fStatus & ( PDMAUDIOSTREAM_STS_INITIALIZED 432 | PDMAUDIOSTREAM_STS_ENABLED 433 | PDMAUDIOSTREAM_STS_PAUSED 434 | PDMAUDIOSTREAM_STS_NEED_REINIT)) 435 == ( PDMAUDIOSTREAM_STS_INITIALIZED 436 | PDMAUDIOSTREAM_STS_ENABLED); 437 } 438 439 /** 440 * Checks if the stream status is one that can be read from. 441 * 442 * @returns @c true if ready to be read from, @c false if not. 443 * @param fStatus Stream status to evaluate, PDMAUDIOSTREAM_STS_XXX. 444 * @note Only for backend statuses. 445 */ 446 DECLINLINE(bool) PDMAudioStrmStatusBackendCanRead(uint32_t fStatus) 447 { 448 PDMAUDIOSTREAM_STS_ASSERT_VALID_BACKEND(fStatus); 449 AssertReturn(!(fStatus & ~PDMAUDIOSTREAM_STS_VALID_MASK_BACKEND), false); 430 450 return (fStatus & ( PDMAUDIOSTREAM_STS_INITIALIZED 431 451 | PDMAUDIOSTREAM_STS_ENABLED … … 441 461 * @returns @c true if ready to be written to, @c false if not. 442 462 * @param fStatus Stream status to evaluate, PDMAUDIOSTREAM_STS_XXX. 463 * @note Not for backend statuses (use PDMAudioStrmStatusBackendCanWrite)! 443 464 */ 444 465 DECLINLINE(bool) PDMAudioStrmStatusCanWrite(uint32_t fStatus) … … 456 477 457 478 /** 479 * Checks if the stream status is one that can be written to, backend edition. 480 * 481 * @returns @c true if ready to be written to, @c false if not. 482 * @param fStatus Stream status to evaluate, PDMAUDIOSTREAM_STS_XXX. 483 * @note Only for backend statuses. 484 */ 485 DECLINLINE(bool) PDMAudioStrmStatusBackendCanWrite(uint32_t fStatus) 486 { 487 PDMAUDIOSTREAM_STS_ASSERT_VALID_BACKEND(fStatus); 488 AssertReturn(!(fStatus & ~PDMAUDIOSTREAM_STS_VALID_MASK_BACKEND), false); 489 return (fStatus & ( PDMAUDIOSTREAM_STS_INITIALIZED 490 | PDMAUDIOSTREAM_STS_ENABLED 491 | PDMAUDIOSTREAM_STS_PAUSED 492 | PDMAUDIOSTREAM_STS_PENDING_DISABLE)) 493 == ( PDMAUDIOSTREAM_STS_INITIALIZED 494 | PDMAUDIOSTREAM_STS_ENABLED); 495 } 496 497 /** 458 498 * Checks if the stream status is a read-to-operate one. 459 499 * 460 500 * @returns @c true if ready to operate, @c false if not. 461 501 * @param fStatus Stream status to evaluate, PDMAUDIOSTREAM_STS_XXX. 502 * @note Not for backend statuses! 462 503 */ 463 504 DECLINLINE(bool) PDMAudioStrmStatusIsReady(uint32_t fStatus) -
trunk/src/VBox/Devices/Audio/DrvAudio.cpp
r88733 r88760 62 62 63 63 /** 64 * Play state of a stream wrt backend. 65 */ 66 typedef enum DRVAUDIOPLAYSTATE 67 { 68 /** Invalid zero value. */ 69 DRVAUDIOPLAYSTATE_INVALID = 0, 70 /** No playback or pre-buffering. */ 71 DRVAUDIOPLAYSTATE_NOPLAY, 72 /** Playing w/o any prebuffering. */ 73 DRVAUDIOPLAYSTATE_PLAY, 74 /** Parallel pre-buffering prior to a device switch (i.e. we're outputting to 75 * the old device and pre-buffering the same data in parallel). */ 76 DRVAUDIOPLAYSTATE_PLAY_PREBUF, 77 /** Initial pre-buffering or the pre-buffering for a device switch (if it 78 * the device setup took less time than filling up the pre-buffer). */ 79 DRVAUDIOPLAYSTATE_PREBUF, 80 /** The device initialization is taking too long, pre-buffering wraps around 81 * and drops samples. */ 82 DRVAUDIOPLAYSTATE_PREBUF_OVERDUE, 83 /** Same as play-prebuf, but we don't have a working output device any more. */ 84 DRVAUDIOPLAYSTATE_PREBUF_SWITCHING, 85 /** Working on committing the pre-buffered data. 86 * We'll typically leave this state immediately and go to PLAY, however if 87 * the backend cannot handle all the pre-buffered data at once, we'll stay 88 * here till it does. */ 89 DRVAUDIOPLAYSTATE_PREBUF_COMMITTING, 90 /** End of valid values. */ 91 DRVAUDIOPLAYSTATE_END 92 } DRVAUDIOPLAYSTATE; 93 94 95 /** 64 96 * Extended stream structure. 65 97 */ … … 82 114 PPDMAUDIOBACKENDSTREAM pBackend; 83 115 84 /** For output streams this indicates whether the stream has reached85 * its playback threshold, e.g. is playing audio.86 * For input streams this indicates whether the stream has enough input87 * data to actually start reading audio. */88 bool fThresholdReached;89 116 /** Do not use the mixing buffers (Guest::MixBuf, Host::MixBuf). */ 90 117 bool fNoMixBufs; 91 bool afPadding[ 2];118 bool afPadding[3]; 92 119 93 120 /** Number of (re-)tries while re-initializing the stream. */ 94 121 uint32_t cTriesReInit; 122 123 /** The backend status at the last play or capture call. 124 * This is used to detect state changes. */ 125 uint32_t fLastBackendStatus; 95 126 96 127 /** The guest side of the stream. */ … … 162 193 /** The size of the pre-buffer allocation (in bytes). */ 163 194 uint32_t cbPreBufAlloc; 195 /** The current pre-buffering read offset. */ 196 uint32_t offPreBuf; 164 197 /** Number of bytes we've prebuffered. */ 165 198 uint32_t cbPreBuffered; 166 199 /** The pre-buffering threshold expressed in bytes. */ 167 200 uint32_t cbPreBufThreshold; 168 169 /** Hack alert: Max writable amount reported by the backend. 170 * This is used to aid buffer underrun detection in DrvAudio while playing. 171 * Ideally, the backend should have a method for querying number of buffered 172 * bytes instead. However this will do for now. */ 173 uint32_t cbBackendMaxWritable; 201 /** The play state. */ 202 DRVAUDIOPLAYSTATE enmPlayState; 174 203 } Out; 175 204 } RT_UNION_NM(u); … … 230 259 /** Friendly name of the driver. */ 231 260 char szName[64]; 232 /** Critical section for serializing access. */ 261 /** Critical section for serializing access. 262 * @todo r=bird: This needs to be split up and introduce stream-level locking so 263 * that different AIO threads can work in parallel (e.g. input & 264 * output, or two output streams). Maybe put a critect in 265 * PDMAUDIOSTREAM? */ 233 266 RTCRITSECT CritSect; 234 267 /** Shutdown indicator. */ 235 268 bool fTerminate; 236 269 #ifdef VBOX_WITH_AUDIO_ENUM 237 /** Flag indicating to perform an (re-)enumeration of the host audio devices. */ 270 /** Flag indicating that we need to enumerate and log of the host 271 * audio devices again. */ 238 272 bool fEnumerateDevices; 239 273 #endif … … 307 341 308 342 309 #ifndef VBOX_AUDIO_TESTCASE 310 # ifdef LOG_ENABLED 343 #ifdef LOG_ENABLED 311 344 312 345 /** Buffer size for dbgAudioStreamStatusToStr. */ 313 # define DRVAUDIO_STATUS_STR_MAX sizeof("INITIALIZED ENABLED PAUSED PENDING_DISABLED PENDING_REINIT0x12345678")346 # define DRVAUDIO_STATUS_STR_MAX sizeof("INITIALIZED ENABLED PAUSED PENDING_DISABLED NEED_REINIT PREPARING_SWITCH 0x12345678") 314 347 315 348 /** … … 330 363 } s_aFlags[] = 331 364 { 332 { RT_STR_TUPLE("INITIALIZED "), PDMAUDIOSTREAM_STS_INITIALIZED }, 333 { RT_STR_TUPLE("ENABLED "), PDMAUDIOSTREAM_STS_ENABLED }, 334 { RT_STR_TUPLE("PAUSED "), PDMAUDIOSTREAM_STS_PAUSED }, 335 { RT_STR_TUPLE("PENDING_DISABLE "), PDMAUDIOSTREAM_STS_PENDING_DISABLE }, 336 { RT_STR_TUPLE("NEED_REINIT "), PDMAUDIOSTREAM_STS_NEED_REINIT }, 365 { RT_STR_TUPLE("INITIALIZED "), PDMAUDIOSTREAM_STS_INITIALIZED }, 366 { RT_STR_TUPLE("ENABLED "), PDMAUDIOSTREAM_STS_ENABLED }, 367 { RT_STR_TUPLE("PAUSED "), PDMAUDIOSTREAM_STS_PAUSED }, 368 { RT_STR_TUPLE("PENDING_DISABLE "), PDMAUDIOSTREAM_STS_PENDING_DISABLE }, 369 { RT_STR_TUPLE("NEED_REINIT "), PDMAUDIOSTREAM_STS_NEED_REINIT }, 370 { RT_STR_TUPLE("PREPARING_SWITCH "), PDMAUDIOSTREAM_STS_PREPARING_SWITCH }, 337 371 }; 338 372 if (!fStatus) … … 359 393 } 360 394 361 # endif /* defined(LOG_ENABLED) */ 362 #endif /* !VBOX_AUDIO_TESTCASE */ 395 #endif /* defined(LOG_ENABLED) */ 396 397 /** 398 * Get pre-buffer state name string. 399 */ 400 static const char *drvAudioPlayStateName(DRVAUDIOPLAYSTATE enmState) 401 { 402 switch (enmState) 403 { 404 case DRVAUDIOPLAYSTATE_INVALID: return "INVALID"; 405 case DRVAUDIOPLAYSTATE_NOPLAY: return "NOPLAY"; 406 case DRVAUDIOPLAYSTATE_PLAY: return "PLAY"; 407 case DRVAUDIOPLAYSTATE_PLAY_PREBUF: return "PLAY_PREBUF"; 408 case DRVAUDIOPLAYSTATE_PREBUF: return "PREBUF"; 409 case DRVAUDIOPLAYSTATE_PREBUF_OVERDUE: return "PREBUF_OVERDUE"; 410 case DRVAUDIOPLAYSTATE_PREBUF_SWITCHING: return "PREBUF_SWITCHING"; 411 case DRVAUDIOPLAYSTATE_PREBUF_COMMITTING: return "PREBUF_COMMITTING"; 412 case DRVAUDIOPLAYSTATE_END: 413 break; 414 } 415 return "BAD"; 416 } 417 418 419 /** 420 * Wrapper around PDMIHOSTAUDIO::pfnStreamGetStatus and checks the result. 421 * 422 * @returns PDMAUDIOSTREAM_STS_XXX 423 * @param pThis Pointer to the DrvAudio instance data. 424 * @param pStreamEx The stream to get the backend status for. 425 */ 426 DECLINLINE(uint32_t) drvAudioStreamGetBackendStatus(PDRVAUDIO pThis, PDRVAUDIOSTREAM pStreamEx) 427 { 428 Assert(pThis->pHostDrvAudio); 429 uint32_t fBackendStatus = pThis->pHostDrvAudio->pfnStreamGetStatus(pThis->pHostDrvAudio, pStreamEx->pBackend); 430 PDMAUDIOSTREAM_STS_ASSERT_VALID_BACKEND(fBackendStatus); 431 return fBackendStatus; 432 } 363 433 364 434 … … 914 984 VERR_INVALID_PARAMETER); 915 985 916 pStreamEx->Core.fStatus |= PDMAUDIOSTREAM_STS_INITIALIZED; 986 pStreamEx->fLastBackendStatus = drvAudioStreamGetBackendStatus(pThis, pStreamEx); 987 pStreamEx->Core.fStatus |= PDMAUDIOSTREAM_STS_INITIALIZED; 917 988 PDMAUDIOSTREAM_STS_ASSERT_VALID(pStreamEx->Core.fStatus); 918 989 … … 1061 1132 Assert(pStreamEx->Out.cbPreBufThreshold == 0); 1062 1133 Assert(pStreamEx->Out.cbPreBuffered == 0); 1134 Assert(pStreamEx->Out.offPreBuf == 0); 1063 1135 if (CfgHostAcq.Backend.cFramesPreBuffering != 0) 1064 1136 { 1065 1137 pStreamEx->Out.cbPreBufThreshold = PDMAudioPropsFramesToBytes(&CfgHostAcq.Props, CfgHostAcq.Backend.cFramesPreBuffering); 1066 pStreamEx->Out.cbPreBufAlloc = PDMAudioPropsFramesToBytes(&CfgHostAcq.Props, CfgHostAcq.Backend.cFramesBufferSize - 2); 1067 pStreamEx->Out.cbPreBufAlloc = RT_MIN(RT_ALIGN_32(pStreamEx->Out.cbPreBufThreshold + _8K, _4K), 1068 pStreamEx->Out.cbPreBufAlloc); 1069 pStreamEx->Out.pbPreBuf = (uint8_t *)RTMemAllocZ(pStreamEx->Out.cbPreBufAlloc); 1138 pStreamEx->Out.cbPreBufAlloc = PDMAudioPropsFramesToBytes(&CfgHostAcq.Props, 1139 CfgHostAcq.Backend.cFramesBufferSize - 2); 1140 pStreamEx->Out.cbPreBufAlloc = RT_MIN(RT_ALIGN_32(pStreamEx->Out.cbPreBufThreshold + _8K, _4K), 1141 pStreamEx->Out.cbPreBufAlloc); 1142 pStreamEx->Out.pbPreBuf = (uint8_t *)RTMemAllocZ(pStreamEx->Out.cbPreBufAlloc); 1070 1143 AssertReturn(pStreamEx->Out.pbPreBuf, VERR_NO_MEMORY); 1071 1144 } 1145 pStreamEx->Out.enmPlayState = DRVAUDIOPLAYSTATE_NOPLAY; /* Changed upon enable. */ 1072 1146 } 1073 1147 … … 1374 1448 pStreamEx->Out.cbPreBufAlloc = 0; 1375 1449 pStreamEx->Out.cbPreBuffered = 0; 1450 pStreamEx->Out.offPreBuf = 0; 1376 1451 } 1377 1452 … … 1477 1552 * drvAudioStreamReInitInternal(). 1478 1553 * 1479 * @param pThis Pointer to driver instance.1480 1554 * @param pStreamEx Stream to drop data for. 1481 1555 */ 1482 static void drvAudioStreamDropInternal(PDRVAUDIO pThis, PDRVAUDIOSTREAM pStreamEx) 1483 { 1484 RT_NOREF(pThis); 1485 1556 static void drvAudioStreamDropInternal(PDRVAUDIOSTREAM pStreamEx) 1557 { 1486 1558 LogFunc(("[%s]\n", pStreamEx->Core.szName)); 1487 1559 … … 1492 1564 } 1493 1565 1494 pStreamEx->fThresholdReached = false;1495 1566 pStreamEx->nsLastIterated = 0; 1496 1567 pStreamEx->nsLastPlayedCaptured = 0; 1497 1568 pStreamEx->nsLastReadWritten = 0; 1569 if (pStreamEx->Host.Cfg.enmDir == PDMAUDIODIR_OUT) 1570 { 1571 pStreamEx->Out.cbPreBuffered = 0; 1572 pStreamEx->Out.offPreBuf = 0; 1573 pStreamEx->Out.enmPlayState = pStreamEx->Out.cbPreBufThreshold > 0 1574 ? DRVAUDIOPLAYSTATE_PREBUF : DRVAUDIOPLAYSTATE_PLAY; 1575 } 1498 1576 } 1499 1577 … … 1524 1602 const bool fIsEnabled = RT_BOOL(pStreamEx->Core.fStatus & PDMAUDIOSTREAM_STS_ENABLED); /* Stream is enabled? */ 1525 1603 1604 /** @todo r=bird: this is retried a bit too indiscriminately for my taste ... */ 1526 1605 /* 1527 1606 * Destroy and re-create stream on backend side. … … 1547 1626 1548 1627 /* Drop all old data. */ 1549 drvAudioStreamDropInternal(p This, pStreamEx);1628 drvAudioStreamDropInternal(pStreamEx); 1550 1629 1551 1630 /* … … 1586 1665 /* Throttle re-initializing streams on failure. */ 1587 1666 if ( pStreamEx->cTriesReInit < cMaxTries 1588 && tsNowNs - pStreamEx->nsLastReInit >= RT_NS_1SEC * pStreamEx->cTriesReInit) /** @todo Ditto. */ 1667 && ( pStreamEx->nsLastReInit == 0 1668 || tsNowNs - pStreamEx->nsLastReInit >= RT_NS_1SEC * pStreamEx->cTriesReInit)) /** @todo Ditto. */ 1589 1669 { 1590 1670 #ifdef VBOX_WITH_AUDIO_ENUM 1671 /** @todo do this elsewhere. */ 1591 1672 if (pThis->fEnumerateDevices) 1592 1673 { … … 1623 1704 /* Did we exceed our tries re-initializing the stream? 1624 1705 * Then this one is dead-in-the-water, so disable it for further use. */ 1706 /** @todo r=bird: This should be done above when drvAudioStreamReInitInternal fails! Duh^2! */ 1625 1707 if (pStreamEx->cTriesReInit == cMaxTries) 1626 1708 { … … 1798 1880 * Resets the given audio stream. 1799 1881 * 1800 * @param pThis Pointer to driver instance.1801 1882 * @param pStreamEx Stream to reset. 1802 1883 */ 1803 static void drvAudioStreamResetInternal(PDRVAUDIO pThis, PDRVAUDIOSTREAM pStreamEx)1804 { 1805 drvAudioStreamDropInternal(p This, pStreamEx);1884 static void drvAudioStreamResetInternal(PDRVAUDIOSTREAM pStreamEx) 1885 { 1886 drvAudioStreamDropInternal(pStreamEx); 1806 1887 1807 1888 LogFunc(("[%s]\n", pStreamEx->Core.szName)); … … 1903 1984 if (pStreamEx->Core.fStatus & PDMAUDIOSTREAM_STS_PENDING_DISABLE) 1904 1985 rc = drvAudioStreamControlInternalBackend(pThis, pStreamEx, PDMAUDIOSTREAMCMD_DISABLE); 1905 1906 if (RT_SUCCESS(rc))1907 rc = drvAudioStreamControlInternalBackend(pThis, pStreamEx, PDMAUDIOSTREAMCMD_ENABLE);1908 1909 1986 if (RT_SUCCESS(rc)) 1910 1987 { 1911 pStreamEx->Core.fStatus |= PDMAUDIOSTREAM_STS_ENABLED; 1912 PDMAUDIOSTREAM_STS_ASSERT_VALID(pStreamEx->Core.fStatus); 1988 /* Reset the play state before we try to start. */ 1989 pStreamEx->fLastBackendStatus = drvAudioStreamGetBackendStatus(pThis, pStreamEx); 1990 if (pStreamEx->Core.enmDir == PDMAUDIODIR_OUT) 1991 { 1992 pStreamEx->Out.cbPreBuffered = 0; 1993 pStreamEx->Out.offPreBuf = 0; 1994 pStreamEx->Out.enmPlayState = pStreamEx->Out.cbPreBufThreshold > 0 1995 ? DRVAUDIOPLAYSTATE_PREBUF 1996 : pStreamEx->fLastBackendStatus & PDMAUDIOSTREAM_STS_INITIALIZED 1997 ? DRVAUDIOPLAYSTATE_PLAY 1998 : DRVAUDIOPLAYSTATE_NOPLAY; 1999 LogFunc(("ENABLE: fLastBackendStatus=%#x enmPlayState=%s\n", 2000 pStreamEx->fLastBackendStatus, drvAudioPlayStateName(pStreamEx->Out.enmPlayState))); 2001 } 2002 else 2003 LogFunc(("ENABLE: fLastBackendStatus=%#x\n", pStreamEx->fLastBackendStatus)); 2004 2005 rc = drvAudioStreamControlInternalBackend(pThis, pStreamEx, PDMAUDIOSTREAMCMD_ENABLE); 2006 if (RT_SUCCESS(rc)) 2007 { 2008 pStreamEx->Core.fStatus |= PDMAUDIOSTREAM_STS_ENABLED; 2009 PDMAUDIOSTREAM_STS_ASSERT_VALID(pStreamEx->Core.fStatus); 2010 } 1913 2011 } 1914 2012 } … … 1949 2047 rc = drvAudioStreamControlInternalBackend(pThis, pStreamEx, PDMAUDIOSTREAMCMD_DISABLE); 1950 2048 if (RT_SUCCESS(rc)) 1951 drvAudioStreamResetInternal(p This, pStreamEx);2049 drvAudioStreamResetInternal(pStreamEx); 1952 2050 } 1953 2051 } … … 2025 2123 2026 2124 /** 2125 * Copy data to the pre-buffer, ring-buffer style. 2126 * 2127 * This is used in two slightly different situations: 2128 * 2129 * -# When the stream is started (enabled) and we only want to prebuffer up 2130 * to the threshold before pushing the data to the backend. We 2131 * typically use the max buffer size for this situation. 2132 * 2133 * -# When the backend sets the PDMAUDIOSTREAM_STS_PREPARING_SWITCH 2134 * status bit and we're preparing for a smooth switch over to a 2135 * different audio device. Most of the pre-buffered data should not be 2136 * played on the old device prior to the switch, due to the prebuffering 2137 * at the start of the stream. We only use the threshold size for this 2138 * case. 2139 */ 2140 static int drvAudioStreamPreBuffer(PDRVAUDIOSTREAM pStreamEx, const uint8_t *pbBuf, uint32_t cbBuf, uint32_t cbMax) 2141 { 2142 uint32_t const cbAlloc = pStreamEx->Out.cbPreBufAlloc; 2143 AssertReturn(cbAlloc >= cbMax, VERR_INTERNAL_ERROR_3); 2144 AssertReturn(cbAlloc >= 8, VERR_INTERNAL_ERROR_4); 2145 AssertReturn(cbMax >= 8, VERR_INTERNAL_ERROR_5); 2146 2147 uint32_t offRead = pStreamEx->Out.offPreBuf; 2148 uint32_t cbCur = pStreamEx->Out.cbPreBuffered; 2149 AssertStmt(offRead < cbAlloc, offRead %= cbAlloc); 2150 AssertStmt(cbCur <= cbMax, offRead = (offRead + cbCur - cbMax) % cbAlloc; cbCur = cbMax); 2151 2152 /* 2153 * First chunk. 2154 */ 2155 uint32_t offWrite = (offRead + cbCur) % cbAlloc; 2156 uint32_t cbToCopy = RT_MIN(cbAlloc - offWrite, cbBuf); 2157 memcpy(&pStreamEx->Out.pbPreBuf[offWrite], pbBuf, cbToCopy); 2158 2159 /* Advance. */ 2160 offWrite = (offWrite + cbToCopy) % cbAlloc; 2161 for (;;) 2162 { 2163 pbBuf += cbToCopy; 2164 cbCur += cbToCopy; 2165 if (cbCur > cbMax) 2166 offRead = (offRead + cbCur - cbMax) % cbAlloc; 2167 cbBuf -= cbToCopy; 2168 if (!cbBuf) 2169 break; 2170 2171 /* 2172 * Second+ chunk, from the start of the buffer. 2173 * 2174 * Note! It is assumed very unlikely that we will ever see a cbBuf larger than 2175 * cbMax, so we don't waste space on clipping cbBuf here (can happen with 2176 * custom pre-buffer sizes). 2177 */ 2178 Assert(offWrite == 0); 2179 cbToCopy = RT_MIN(cbAlloc, cbBuf); 2180 memcpy(pStreamEx->Out.pbPreBuf, pbBuf, cbToCopy); 2181 } 2182 2183 /* 2184 * Update the pre-buffering size and position. 2185 */ 2186 pStreamEx->Out.cbPreBuffered = cbCur; 2187 pStreamEx->Out.offPreBuf = offRead; 2188 return VINF_SUCCESS; 2189 } 2190 2191 2192 #if 0 2193 /** 2027 2194 * Worker for drvAudioStreamPlay() and drvAudioStreamIterateInternal(). 2028 2195 * … … 2066 2233 cbWritten = RT_MIN(cbFree, cbBuf); 2067 2234 cbWritten = PDMAudioPropsFloorBytesToFrame(&pStreamEx->Core.Props, cbWritten); 2068 memcpy(&pStreamEx->Out.pbPreBuf[pStreamEx->Out.cbPreBuffered], pbBuf, cbWritten); 2235 if (pStreamEx->Out.offPreBuf == 0) 2236 memcpy(&pStreamEx->Out.pbPreBuf[pStreamEx->Out.cbPreBuffered], pbBuf, cbWritten); 2237 else 2238 { 2239 2240 } 2241 2069 2242 pStreamEx->Out.cbPreBuffered += cbWritten; 2070 2243 cbBuf -= cbWritten; … … 2206 2379 return rc; 2207 2380 } 2381 #endif 2382 2383 2384 /** 2385 * Worker for drvAudioStreamPlay() and drvAudioStreamIterateInternal(). 2386 * 2387 * Caller owns the lock. 2388 */ 2389 static int drvAudioStreamPlayLocked(PDRVAUDIO pThis, PDRVAUDIOSTREAM pStreamEx, 2390 const uint8_t *pbBuf, uint32_t cbBuf, uint32_t *pcbWritten) 2391 { 2392 Log3Func(("%s: @%#RX64: cbBuf=%#x\n", pStreamEx->Core.szName, pStreamEx->offInternal, cbBuf)); 2393 2394 uint32_t cbWritable = pThis->pHostDrvAudio->pfnStreamGetWritable(pThis->pHostDrvAudio, pStreamEx->pBackend); 2395 pStreamEx->Out.Stats.cbBackendWritableBefore = cbWritable; 2396 2397 uint32_t cbWritten = 0; 2398 int rc = VINF_SUCCESS; 2399 uint8_t const cbFrame = PDMAudioPropsFrameSize(&pStreamEx->Core.Props); 2400 while (cbBuf >= cbFrame && cbWritable >= cbFrame) 2401 { 2402 uint32_t const cbToWrite = PDMAudioPropsFloorBytesToFrame(&pStreamEx->Core.Props, RT_MIN(cbBuf, cbWritable)); 2403 uint32_t cbWrittenNow = 0; 2404 rc = pThis->pHostDrvAudio->pfnStreamPlay(pThis->pHostDrvAudio, pStreamEx->pBackend, pbBuf, cbToWrite, &cbWrittenNow); 2405 if (RT_SUCCESS(rc)) 2406 { 2407 if (cbWrittenNow != cbToWrite) 2408 Log3Func(("%s: @%#RX64: Wrote less bytes than requested: %#x, requested %#x\n", 2409 pStreamEx->Core.szName, pStreamEx->offInternal, cbWrittenNow, cbToWrite)); 2410 #ifdef DEBUG_bird 2411 Assert(cbWrittenNow == cbToWrite); 2412 #endif 2413 AssertStmt(cbWrittenNow <= cbToWrite, cbWrittenNow = cbToWrite); 2414 cbWritten += cbWrittenNow; 2415 cbBuf -= cbWrittenNow; 2416 pbBuf += cbWrittenNow; 2417 pStreamEx->offInternal += cbWrittenNow; 2418 } 2419 else 2420 { 2421 *pcbWritten = cbWritten; 2422 LogFunc(("%s: @%#RX64: pfnStreamPlay failed writing %#x bytes (%#x previous written, %#x writable): %Rrc\n", 2423 pStreamEx->Core.szName, pStreamEx->offInternal, cbToWrite, cbWritten, cbWritable, rc)); 2424 return cbWritten ? VINF_SUCCESS : rc; 2425 } 2426 2427 cbWritable = pThis->pHostDrvAudio->pfnStreamGetWritable(pThis->pHostDrvAudio, pStreamEx->pBackend); 2428 } 2429 2430 *pcbWritten = cbWritten; 2431 pStreamEx->Out.Stats.cbBackendWritableAfter = cbWritable; 2432 if (cbWritten) 2433 pStreamEx->nsLastPlayedCaptured = RTTimeNanoTS(); 2434 2435 Log3Func(("%s: @%#RX64: Wrote %#x bytes (%#x bytes left)\n", pStreamEx->Core.szName, pStreamEx->offInternal, cbWritten, cbBuf)); 2436 return rc; 2437 } 2438 2439 2440 static int drvAudioStreamPlayToPreBuffer(PDRVAUDIOSTREAM pStreamEx, const void *pvBuf, uint32_t cbBuf, uint32_t cbMax, 2441 uint32_t *pcbWritten) 2442 { 2443 int rc = drvAudioStreamPreBuffer(pStreamEx, (uint8_t const *)pvBuf, cbBuf, cbMax); 2444 if (RT_SUCCESS(rc)) 2445 { 2446 *pcbWritten = cbBuf; 2447 pStreamEx->offInternal += cbBuf; 2448 Log3Func(("[%s] Pre-buffering (%s): wrote %#x bytes => %#x bytes / %u%%\n", 2449 pStreamEx->Core.szName, drvAudioPlayStateName(pStreamEx->Out.enmPlayState), cbBuf, pStreamEx->Out.cbPreBuffered, 2450 pStreamEx->Out.cbPreBuffered * 100 / RT_MAX(pStreamEx->Out.cbPreBufThreshold, 1))); 2451 2452 } 2453 else 2454 *pcbWritten = 0; 2455 return rc; 2456 } 2457 2458 2459 /** 2460 * Used when we're committing (transfering) the pre-buffered bytes to the 2461 * device. 2462 * 2463 * This is called both from drvAudioStreamPlay() and 2464 * drvAudioStreamIterateInternal(). 2465 * 2466 * @returns VBox status code. 2467 * @param pThis Pointer to the DrvAudio instance data. 2468 * @param pStreamEx The stream to commit the pre-buffering for. 2469 * @param pbBuf Buffer with new bytes to write. Can be NULL when called 2470 * in the PENDING_DISABLE state from 2471 * drvAudioStreamIterateInternal(). 2472 * @param cbBuf Number of new bytes. Can be zero. 2473 * @param pcbWritten Where to return the number of bytes written. 2474 */ 2475 static int drvAudioStreamPreBufComitting(PDRVAUDIO pThis, PDRVAUDIOSTREAM pStreamEx, 2476 const uint8_t *pbBuf, uint32_t cbBuf, uint32_t *pcbWritten) 2477 { 2478 /* 2479 * First, top up the buffer with new data from pbBuf. 2480 */ 2481 *pcbWritten = 0; 2482 if (cbBuf > 0) 2483 { 2484 uint32_t const cbToCopy = RT_MIN(pStreamEx->Out.cbPreBufAlloc - pStreamEx->Out.cbPreBuffered, cbBuf); 2485 if (cbToCopy > 0) 2486 { 2487 int rc = drvAudioStreamPlayToPreBuffer(pStreamEx, pbBuf, cbBuf, pStreamEx->Out.cbPreBufAlloc, pcbWritten); 2488 AssertRCReturn(rc, rc); 2489 pbBuf += cbToCopy; 2490 cbBuf -= cbToCopy; 2491 } 2492 } 2493 2494 /* 2495 * Write the pre-buffered chunk. 2496 */ 2497 int rc = VINF_SUCCESS; 2498 uint32_t const cbAlloc = pStreamEx->Out.cbPreBufAlloc; 2499 AssertReturn(cbAlloc > 0, VERR_INTERNAL_ERROR_2); 2500 uint32_t off = pStreamEx->Out.offPreBuf; 2501 AssertStmt(off < pStreamEx->Out.cbPreBufAlloc, off %= cbAlloc); 2502 uint32_t cbLeft = pStreamEx->Out.cbPreBuffered; 2503 while (cbLeft > 0) 2504 { 2505 uint32_t const cbToWrite = RT_MIN(cbAlloc - off, cbLeft); 2506 Assert(cbToWrite > 0); 2507 2508 uint32_t cbPreBufWritten = 0; 2509 rc = pThis->pHostDrvAudio->pfnStreamPlay(pThis->pHostDrvAudio, pStreamEx->pBackend, &pStreamEx->Out.pbPreBuf[off], 2510 cbToWrite, &cbPreBufWritten); 2511 AssertRCBreak(rc); 2512 if (!cbPreBufWritten) 2513 break; 2514 AssertStmt(cbPreBufWritten <= cbToWrite, cbPreBufWritten = cbToWrite); 2515 off = (off + cbPreBufWritten) % cbAlloc; 2516 cbLeft -= cbPreBufWritten; 2517 } 2518 2519 if (cbLeft == 0) 2520 { 2521 LogFunc(("@%#RX64: Wrote all %#x bytes of pre-buffered audio data. %s -> PLAY\n", pStreamEx->offInternal, 2522 pStreamEx->Out.cbPreBuffered, drvAudioPlayStateName(pStreamEx->Out.enmPlayState) )); 2523 pStreamEx->Out.cbPreBuffered = 0; 2524 pStreamEx->Out.offPreBuf = 0; 2525 pStreamEx->Out.enmPlayState = DRVAUDIOPLAYSTATE_PLAY; 2526 2527 if (cbBuf > 0) 2528 { 2529 uint32_t cbWritten2 = 0; 2530 rc = drvAudioStreamPlayLocked(pThis, pStreamEx, pbBuf, cbBuf, &cbWritten2); 2531 if (RT_SUCCESS(rc)) 2532 *pcbWritten += cbWritten2; 2533 } 2534 else 2535 pStreamEx->nsLastPlayedCaptured = RTTimeNanoTS(); 2536 } 2537 else 2538 { 2539 if (cbLeft != pStreamEx->Out.cbPreBuffered) 2540 pStreamEx->nsLastPlayedCaptured = RTTimeNanoTS(); 2541 2542 LogRel2(("Audio: @%#RX64: Stream '%s' pre-buffering commit problem: wrote %#x out of %#x + %#x - rc=%Rrc *pcbWritten=%#x %s -> PREBUF_COMMITTING\n", 2543 pStreamEx->offInternal, pStreamEx->Core.szName, pStreamEx->Out.cbPreBuffered - cbLeft, 2544 pStreamEx->Out.cbPreBuffered, cbBuf, rc, *pcbWritten, drvAudioPlayStateName(pStreamEx->Out.enmPlayState) )); 2545 AssertMsg(pStreamEx->Out.enmPlayState == DRVAUDIOPLAYSTATE_PREBUF_COMMITTING || RT_FAILURE(rc), 2546 ("Buggy host driver buffer reporting? cbLeft=%#x cbPreBuffered=%#x\n", cbLeft, pStreamEx->Out.cbPreBuffered)); 2547 2548 pStreamEx->Out.cbPreBuffered = cbLeft; 2549 pStreamEx->Out.offPreBuf = off; 2550 pStreamEx->Out.enmPlayState = DRVAUDIOPLAYSTATE_PREBUF_COMMITTING; 2551 } 2552 2553 return *pcbWritten ? VINF_SUCCESS : rc; 2554 } 2208 2555 2209 2556 … … 2260 2607 * is played. That means that this code and associated timer hack 2261 2608 * should probably not be here at all. */ 2262 uint32_t cFramesLive; 2263 cFramesLive = pStreamEx->Out.cbPreBuffered; 2264 if (cFramesLive > 0) 2265 { 2266 uint32_t cbIgnored = 0; 2267 drvAudioStreamPlayLocked(pThis, pStreamEx, 2268 pThis->pHostDrvAudio->pfnStreamGetStatus(pThis->pHostDrvAudio, pStreamEx->pBackend), 2269 NULL, 0, &cbIgnored); 2270 cFramesLive = PDMAudioPropsBytesToFrames(&pStreamEx->Core.Props, pStreamEx->Out.cbPreBuffered); 2609 uint32_t cFramesLive = 0; 2610 switch (pStreamEx->Out.enmPlayState) 2611 { 2612 case DRVAUDIOPLAYSTATE_PLAY: /* Nothing prebuffered. */ 2613 case DRVAUDIOPLAYSTATE_PLAY_PREBUF: /* Not pre-buffering for current device. */ 2614 case DRVAUDIOPLAYSTATE_PREBUF_OVERDUE: /* Output device isn't ready, drop it. */ /** @todo check state? */ 2615 case DRVAUDIOPLAYSTATE_PREBUF_SWITCHING: /* No output device yet. */ 2616 case DRVAUDIOPLAYSTATE_NOPLAY: 2617 case DRVAUDIOPLAYSTATE_INVALID: 2618 case DRVAUDIOPLAYSTATE_END: 2619 /* no default, want warnings. */ 2620 break; 2621 case DRVAUDIOPLAYSTATE_PREBUF: 2622 case DRVAUDIOPLAYSTATE_PREBUF_COMMITTING: 2623 if (pStreamEx->Out.cbPreBuffered > 0) 2624 { 2625 uint32_t cbIgnored = 0; 2626 drvAudioStreamPreBufComitting(pThis, pStreamEx, NULL, 0, &cbIgnored); 2627 cFramesLive = PDMAudioPropsBytesToFrames(&pStreamEx->Core.Props, pStreamEx->Out.cbPreBuffered); 2628 } 2629 break; 2271 2630 } 2272 2631 Log3Func(("[%s] cFramesLive=%RU32\n", pStreamEx->Core.szName, cFramesLive)); … … 2305 2664 pStreamEx->Core.fStatus &= ~(PDMAUDIOSTREAM_STS_ENABLED | PDMAUDIOSTREAM_STS_PENDING_DISABLE); 2306 2665 PDMAUDIOSTREAM_STS_ASSERT_VALID(pStreamEx->Core.fStatus); 2307 drvAudioStreamDropInternal(p This, pStreamEx); /* Not a DROP command, just a stream reset. */2666 drvAudioStreamDropInternal(pStreamEx); /* Not a DROP command, just a stream reset. */ 2308 2667 } 2309 2668 else … … 2397 2756 * Reading the actual data from a stream then will return silence then. 2398 2757 */ 2399 uint32_t fStatus = pThis->pHostDrvAudio->pfnStreamGetStatus(pThis->pHostDrvAudio, pStreamEx->pBackend);2400 if ( !PDMAudioStrmStatus CanRead(fStatus)2758 uint32_t fStatus = drvAudioStreamGetBackendStatus(pThis, pStreamEx); 2759 if ( !PDMAudioStrmStatusBackendCanRead(fStatus) 2401 2760 || fDisabled) 2402 2761 { … … 2445 2804 /* 2446 2805 * ... 2806 * 2807 * Note: We don't propagate the backend stream's status to the outside -- it's the job of this 2808 * audio connector to make sense of it. 2447 2809 */ 2448 2810 uint32_t cbWritable = 0; 2449 2450 /* Note: We don't propagate the backend stream's status to the outside -- it's the job of this 2451 * audio connector to make sense of it. */ 2452 if (PDMAudioStrmStatusCanWrite(pStreamEx->Core.fStatus)) 2453 { 2454 if (pStreamEx->fNoMixBufs) 2455 { 2456 Assert(pThis->pHostDrvAudio); 2457 cbWritable = pThis->pHostDrvAudio 2458 ? pThis->pHostDrvAudio->pfnStreamGetWritable(pThis->pHostDrvAudio, pStreamEx->pBackend) : 0; 2459 if (pStreamEx->fThresholdReached) 2811 if ( PDMAudioStrmStatusCanWrite(pStreamEx->Core.fStatus) 2812 && pThis->pHostDrvAudio != NULL) 2813 { 2814 Assert(pThis->pHostDrvAudio); 2815 switch (pStreamEx->Out.enmPlayState) 2816 { 2817 /* 2818 * Whatever the backend can hold. 2819 */ 2820 case DRVAUDIOPLAYSTATE_PLAY: 2821 case DRVAUDIOPLAYSTATE_PLAY_PREBUF: 2822 cbWritable = pThis->pHostDrvAudio->pfnStreamGetWritable(pThis->pHostDrvAudio, pStreamEx->pBackend); 2823 break; 2824 2825 /* 2826 * Whatever we've got of available space in the pre-buffer. 2827 * Note! For the last round when we pass the pre-buffering threshold, we may 2828 * report fewer bytes than what a DMA timer period for the guest device 2829 * typically produces, however that should be transfered in the following 2830 * round that goes directly to the backend buffer. 2831 */ 2832 case DRVAUDIOPLAYSTATE_PREBUF: 2833 cbWritable = pStreamEx->Out.cbPreBufAlloc - pStreamEx->Out.cbPreBuffered; 2834 if (!cbWritable) 2835 cbWritable = PDMAudioPropsFramesToBytes(&pStreamEx->Core.Props, 2); 2836 break; 2837 2838 /* 2839 * These are slightly more problematic and can go wrong if the pre-buffer is 2840 * manually configured to be smaller than the output of a typeical DMA timer 2841 * period for the guest device. So, to overcompensate, we just report back 2842 * the backend buffer size (the pre-buffer is circular, so no overflow issue). 2843 */ 2844 case DRVAUDIOPLAYSTATE_PREBUF_OVERDUE: 2845 case DRVAUDIOPLAYSTATE_PREBUF_SWITCHING: 2846 cbWritable = PDMAudioPropsFramesToBytes(&pStreamEx->Core.Props, 2847 RT_MAX(pStreamEx->Host.Cfg.Backend.cFramesBufferSize, 2848 pStreamEx->Host.Cfg.Backend.cFramesPreBuffering)); 2849 break; 2850 2851 case DRVAUDIOPLAYSTATE_PREBUF_COMMITTING: 2460 2852 { 2461 if (pStreamEx->Out.cbPreBuffered == 0) 2462 { /* likely */ } 2853 /* Buggy backend: We weren't able to copy all the pre-buffered data to it 2854 when reaching the threshold. Try escape this situation, or at least 2855 keep the extra buffering to a minimum. We must try write something 2856 as long as there is space for it, as we need the pfnStreamWrite call 2857 to move the data. */ 2858 uint32_t const cbMin = PDMAudioPropsFramesToBytes(&pStreamEx->Core.Props, 8); 2859 cbWritable = pThis->pHostDrvAudio->pfnStreamGetWritable(pThis->pHostDrvAudio, pStreamEx->pBackend); 2860 if (cbWritable >= pStreamEx->Out.cbPreBuffered + cbMin) 2861 cbWritable -= pStreamEx->Out.cbPreBuffered + cbMin / 2; 2463 2862 else 2464 { 2465 /* Buggy backend: We weren't able to copy all the pre-buffered data to it 2466 when reaching the threshold. Try escape this situation, or at least 2467 keep the extra buffering to a minimum. We must try write something 2468 as long as there is space for it, as we need the pfnStreamWrite call 2469 to move the data. */ 2470 uint32_t const cbMin = PDMAudioPropsFramesToBytes(&pStreamEx->Core.Props, 8); 2471 if (cbWritable >= pStreamEx->Out.cbPreBuffered + cbMin) 2472 cbWritable -= pStreamEx->Out.cbPreBuffered + cbMin / 2; 2473 else 2474 cbWritable = RT_MIN(cbMin, pStreamEx->Out.cbPreBufAlloc - pStreamEx->Out.cbPreBuffered); 2475 AssertLogRel(cbWritable); 2476 } 2863 cbWritable = RT_MIN(cbMin, pStreamEx->Out.cbPreBufAlloc - pStreamEx->Out.cbPreBuffered); 2864 AssertLogRel(cbWritable); 2865 break; 2477 2866 } 2478 else 2479 {2480 Assert(cbWritable >= pStreamEx->Out.cbPreBufThreshold);2481 cbWritable = pStreamEx->Out.cbPreBufAlloc - pStreamEx->Out.cbPreBufThreshold;2482 }2483 }2484 else2485 cbWritable = AudioMixBufFreeBytes(&pStreamEx->Host.MixBuf);2867 2868 case DRVAUDIOPLAYSTATE_NOPLAY: 2869 break; 2870 case DRVAUDIOPLAYSTATE_INVALID: 2871 case DRVAUDIOPLAYSTATE_END: 2872 AssertFailed(); 2873 break; 2874 } 2486 2875 2487 2876 /* Make sure to align the writable size to the host's frame size. */ … … 2546 2935 2547 2936 return VINF_SUCCESS; 2937 } 2938 2939 2940 static void drvAudioStreamPlayProcessBackendStateChange(PDRVAUDIOSTREAM pStreamEx, uint32_t fNewState, uint32_t fOldState) 2941 { 2942 DRVAUDIOPLAYSTATE const enmPlayState = pStreamEx->Out.enmPlayState; 2943 2944 /* 2945 * Did PDMAUDIOSTREAM_STS_INITIALIZED change? 2946 */ 2947 if ((fOldState ^ fNewState) & PDMAUDIOSTREAM_STS_INITIALIZED) 2948 { 2949 if (fOldState & PDMAUDIOSTREAM_STS_INITIALIZED) 2950 { 2951 switch (enmPlayState) 2952 { 2953 case DRVAUDIOPLAYSTATE_PLAY: 2954 case DRVAUDIOPLAYSTATE_PREBUF_COMMITTING: 2955 pStreamEx->Out.enmPlayState = DRVAUDIOPLAYSTATE_NOPLAY; 2956 /** @todo We could enter PREBUF here and hope for the device to re-appear in 2957 * initialized state... */ 2958 break; 2959 case DRVAUDIOPLAYSTATE_PLAY_PREBUF: 2960 pStreamEx->Out.enmPlayState = DRVAUDIOPLAYSTATE_PREBUF_SWITCHING; 2961 break; 2962 case DRVAUDIOPLAYSTATE_PREBUF: 2963 break; 2964 case DRVAUDIOPLAYSTATE_PREBUF_OVERDUE: 2965 case DRVAUDIOPLAYSTATE_PREBUF_SWITCHING: 2966 AssertFailedBreak(); 2967 /* no default */ 2968 case DRVAUDIOPLAYSTATE_NOPLAY: 2969 case DRVAUDIOPLAYSTATE_END: 2970 case DRVAUDIOPLAYSTATE_INVALID: 2971 break; 2972 } 2973 LogFunc(("PDMAUDIOSTREAM_STS_INITIALIZED was cleared: %s -> %s\n", 2974 drvAudioPlayStateName(enmPlayState), drvAudioPlayStateName(pStreamEx->Out.enmPlayState) )); 2975 } 2976 else 2977 { 2978 switch (enmPlayState) 2979 { 2980 case DRVAUDIOPLAYSTATE_PREBUF: 2981 case DRVAUDIOPLAYSTATE_PREBUF_SWITCHING: 2982 break; 2983 case DRVAUDIOPLAYSTATE_PREBUF_OVERDUE: 2984 pStreamEx->Out.enmPlayState = DRVAUDIOPLAYSTATE_PREBUF_COMMITTING; 2985 break; 2986 case DRVAUDIOPLAYSTATE_NOPLAY: 2987 pStreamEx->Out.enmPlayState = DRVAUDIOPLAYSTATE_PREBUF; 2988 break; 2989 case DRVAUDIOPLAYSTATE_PLAY: 2990 case DRVAUDIOPLAYSTATE_PLAY_PREBUF: 2991 case DRVAUDIOPLAYSTATE_PREBUF_COMMITTING: 2992 AssertFailedBreak(); 2993 /* no default */ 2994 case DRVAUDIOPLAYSTATE_END: 2995 case DRVAUDIOPLAYSTATE_INVALID: 2996 break; 2997 } 2998 LogFunc(("PDMAUDIOSTREAM_STS_INITIALIZED was set: %s -> %s\n", 2999 drvAudioPlayStateName(enmPlayState), drvAudioPlayStateName(pStreamEx->Out.enmPlayState) )); 3000 } 3001 } 3002 3003 /* 3004 * Deal with PDMAUDIOSTREAM_STS_PREPARING_SWITCH being set. 3005 * 3006 * Note! We don't care if it's cleared as the backend will call 3007 * PDMIAUDIONOTIFYFROMHOST::pfnStreamNotifyDeviceChanged when that takes place. 3008 */ 3009 if ( !(fOldState & PDMAUDIOSTREAM_STS_PREPARING_SWITCH) 3010 && (fNewState & PDMAUDIOSTREAM_STS_PREPARING_SWITCH)) 3011 { 3012 if (pStreamEx->Out.cbPreBufThreshold > 0) 3013 { 3014 switch (enmPlayState) 3015 { 3016 case DRVAUDIOPLAYSTATE_PREBUF: 3017 case DRVAUDIOPLAYSTATE_PREBUF_OVERDUE: 3018 case DRVAUDIOPLAYSTATE_NOPLAY: 3019 case DRVAUDIOPLAYSTATE_PREBUF_COMMITTING: /* simpler */ 3020 pStreamEx->Out.enmPlayState = DRVAUDIOPLAYSTATE_PREBUF_SWITCHING; 3021 break; 3022 case DRVAUDIOPLAYSTATE_PLAY: 3023 pStreamEx->Out.enmPlayState = DRVAUDIOPLAYSTATE_PLAY_PREBUF; 3024 break; 3025 case DRVAUDIOPLAYSTATE_PREBUF_SWITCHING: 3026 case DRVAUDIOPLAYSTATE_PLAY_PREBUF: 3027 break; 3028 /* no default */ 3029 case DRVAUDIOPLAYSTATE_END: 3030 case DRVAUDIOPLAYSTATE_INVALID: 3031 break; 3032 } 3033 LogFunc(("PDMAUDIOSTREAM_STS_INITIALIZED was set: %s -> %s\n", 3034 drvAudioPlayStateName(enmPlayState), drvAudioPlayStateName(pStreamEx->Out.enmPlayState) )); 3035 } 3036 else 3037 LogFunc(("PDMAUDIOSTREAM_STS_PREPARING_SWITCH was set, but no pre-buffering configured.\n")); 3038 } 2548 3039 } 2549 3040 … … 2590 3081 if (PDMAudioStrmStatusIsReady(pStreamEx->Core.fStatus)) 2591 3082 { 2592 uint32_t fBackStatus;2593 3083 if ( pThis->Out.fEnabled /* (see @bugref{9882}) */ 2594 && pThis->pHostDrvAudio != NULL 2595 && PDMAudioStrmStatusCanWrite((fBackStatus = pThis->pHostDrvAudio->pfnStreamGetStatus(pThis->pHostDrvAudio, 2596 pStreamEx->pBackend)))) 2597 { 2598 uint64_t offInternalBefore = pStreamEx->offInternal; RT_NOREF(offInternalBefore); 2599 rc = drvAudioStreamPlayLocked(pThis, pStreamEx, fBackStatus, (uint8_t const *)pvBuf, cbBuf, pcbWritten); 2600 Assert(offInternalBefore + *pcbWritten == pStreamEx->offInternal); 3084 && pThis->pHostDrvAudio != NULL) 3085 { 3086 #ifdef LOG_ENABLED 3087 char szState[DRVAUDIO_STATUS_STR_MAX]; 3088 #endif 3089 /* 3090 * Get the backend state and check if we've changed to "initialized" or 3091 * to switch prep mode. 3092 * 3093 * We don't really need to watch ENABLE or PAUSE here as these should be 3094 * in sync between our state and the backend (there is a tiny tiny chance 3095 * that we are resumed before the backend driver, but AIO threads really 3096 * shouldn't be getting here that fast I hope). 3097 */ 3098 /** @todo 3099 * The PENDING_DISABLE (== draining) is not reported by most backend and it's an 3100 * open question whether we should still allow writes even when the backend 3101 * is draining anyway. We currently don't. Maybe we just re-define it as 3102 * a non-backend status flag. 3103 */ 3104 uint32_t const fBackendStatus = drvAudioStreamGetBackendStatus(pThis, pStreamEx); 3105 Assert( (fBackendStatus & (PDMAUDIOSTREAM_STS_ENABLED | PDMAUDIOSTREAM_STS_PAUSED)) 3106 == (pStreamEx->Core.fStatus & (PDMAUDIOSTREAM_STS_ENABLED | PDMAUDIOSTREAM_STS_PAUSED)) ); 3107 3108 if (!( (pStreamEx->fLastBackendStatus ^ fBackendStatus) 3109 & (PDMAUDIOSTREAM_STS_INITIALIZED | PDMAUDIOSTREAM_STS_PREPARING_SWITCH))) 3110 { /* no relevant change - likely */ } 3111 else 3112 { 3113 drvAudioStreamPlayProcessBackendStateChange(pStreamEx, fBackendStatus, pStreamEx->fLastBackendStatus); 3114 pStreamEx->fLastBackendStatus = fBackendStatus; 3115 } 3116 3117 /* 3118 * Do the transfering. 3119 */ 3120 switch (pStreamEx->Out.enmPlayState) 3121 { 3122 case DRVAUDIOPLAYSTATE_PLAY: 3123 rc = drvAudioStreamPlayLocked(pThis, pStreamEx, (uint8_t const *)pvBuf, cbBuf, pcbWritten); 3124 break; 3125 3126 case DRVAUDIOPLAYSTATE_PLAY_PREBUF: 3127 rc = drvAudioStreamPlayLocked(pThis, pStreamEx, (uint8_t const *)pvBuf, cbBuf, pcbWritten); 3128 drvAudioStreamPreBuffer(pStreamEx, (uint8_t const *)pvBuf, *pcbWritten, pStreamEx->Out.cbPreBufThreshold); 3129 break; 3130 3131 case DRVAUDIOPLAYSTATE_PREBUF: 3132 if (cbBuf + pStreamEx->Out.cbPreBuffered < pStreamEx->Out.cbPreBufThreshold) 3133 rc = drvAudioStreamPlayToPreBuffer(pStreamEx, pvBuf, cbBuf, pStreamEx->Out.cbPreBufThreshold, pcbWritten); 3134 else if (fBackendStatus & PDMAUDIOSTREAM_STS_INITIALIZED) 3135 { 3136 Log3Func(("[%s] Pre-buffering completing: cbBuf=%#x cbPreBuffered=%#x => %#x vs cbPreBufThreshold=%#x\n", 3137 pStreamEx->Core.szName, cbBuf, pStreamEx->Out.cbPreBuffered, 3138 cbBuf + pStreamEx->Out.cbPreBuffered, pStreamEx->Out.cbPreBufThreshold)); 3139 rc = drvAudioStreamPreBufComitting(pThis, pStreamEx, (uint8_t const *)pvBuf, cbBuf, pcbWritten); 3140 } 3141 else 3142 { 3143 Log3Func(("[%s] Pre-buffering completing but device not ready: cbBuf=%#x cbPreBuffered=%#x => %#x vs cbPreBufThreshold=%#x; PREBUF -> PREBUF_OVERDUE\n", 3144 pStreamEx->Core.szName, cbBuf, pStreamEx->Out.cbPreBuffered, 3145 cbBuf + pStreamEx->Out.cbPreBuffered, pStreamEx->Out.cbPreBufThreshold)); 3146 pStreamEx->Out.enmPlayState = DRVAUDIOPLAYSTATE_PREBUF_OVERDUE; 3147 rc = drvAudioStreamPlayToPreBuffer(pStreamEx, pvBuf, cbBuf, pStreamEx->Out.cbPreBufThreshold, pcbWritten); 3148 } 3149 break; 3150 3151 case DRVAUDIOPLAYSTATE_PREBUF_OVERDUE: 3152 Assert(!(fBackendStatus & PDMAUDIOSTREAM_STS_INITIALIZED)); 3153 RT_FALL_THRU(); 3154 case DRVAUDIOPLAYSTATE_PREBUF_SWITCHING: 3155 rc = drvAudioStreamPlayToPreBuffer(pStreamEx, pvBuf, cbBuf, pStreamEx->Out.cbPreBufThreshold, pcbWritten); 3156 break; 3157 3158 case DRVAUDIOPLAYSTATE_PREBUF_COMMITTING: 3159 rc = drvAudioStreamPreBufComitting(pThis, pStreamEx, (uint8_t const *)pvBuf, cbBuf, pcbWritten); 3160 break; 3161 3162 case DRVAUDIOPLAYSTATE_NOPLAY: 3163 *pcbWritten = cbBuf; 3164 pStreamEx->offInternal += cbBuf; 3165 Log3Func(("[%s] Discarding the data, backend state: %s\n", pStreamEx->Core.szName, 3166 dbgAudioStreamStatusToStr(szState, fBackendStatus) )); 3167 break; 3168 3169 default: 3170 *pcbWritten = cbBuf; 3171 AssertMsgFailedBreak(("%d; cbBuf=%#x\n", pStreamEx->Out.enmPlayState, cbBuf)); 3172 } 3173 2601 3174 if (!pThis->Out.Cfg.Dbg.fEnabled || RT_FAILURE(rc)) 2602 3175 { /* likely */ } 2603 3176 else 2604 3177 AudioHlpFileWrite(pStreamEx->Out.Dbg.pFilePlayNonInterleaved, pvBuf, *pcbWritten, 0 /* fFlags */); 2605 2606 3178 } 2607 3179 else 2608 3180 { 3181 *pcbWritten = cbBuf; 3182 pStreamEx->offInternal += cbBuf; 2609 3183 Log3Func(("[%s] Backend stream %s, discarding the data\n", pStreamEx->Core.szName, 2610 3184 !pThis->Out.fEnabled ? "disabled" : !pThis->pHostDrvAudio ? "not attached" : "not ready yet")); 2611 *pcbWritten = cbBuf;2612 pStreamEx->offInternal += cbBuf;2613 3185 } 2614 3186 } … … 2986 3558 2987 3559 /** 2988 * Schedules a re-initialization of all current audio streams. 2989 * The actual re-initialization will happen at some later point in time. 2990 * 2991 * @param pThis Pointer to driver instance. 2992 */ 2993 static void drvAudioScheduleReInitInternal(PDRVAUDIO pThis) 2994 { 2995 LogFunc(("\n")); 2996 2997 /* Mark all host streams to re-initialize. */ 3560 * Marks a stream for re-init. 3561 */ 3562 static void drvAudioStreamMarkNeedReInit(PDRVAUDIOSTREAM pStreamEx, const char *pszCaller) 3563 { 3564 LogFlow((LOG_FN_FMT ": Flagging %s for re-init.\n", pStreamEx->Core.szName)); RT_NOREF(pszCaller); 3565 pStreamEx->Core.fStatus |= PDMAUDIOSTREAM_STS_NEED_REINIT; 3566 PDMAUDIOSTREAM_STS_ASSERT_VALID(pStreamEx->Core.fStatus); 3567 pStreamEx->cTriesReInit = 0; 3568 pStreamEx->nsLastReInit = 0; 3569 } 3570 3571 3572 /** 3573 * @interface_method_impl{PDMIAUDIONOTIFYFROMHOST,pfnNotifyDeviceChanged} 3574 */ 3575 static DECLCALLBACK(void) drvAudioNotifyFromHost_NotifyDeviceChanged(PPDMIAUDIONOTIFYFROMHOST pInterface, 3576 PDMAUDIODIR enmDir, void *pvUser) 3577 { 3578 PDRVAUDIO pThis = RT_FROM_MEMBER(pInterface, DRVAUDIO, IAudioNotifyFromHost); 3579 AssertReturnVoid(enmDir == PDMAUDIODIR_IN || enmDir == PDMAUDIODIR_OUT); 3580 LogRel(("Audio: The %s device for %s is changing.\n", enmDir == PDMAUDIODIR_IN ? "input" : "output", pThis->szName)); 3581 3582 RTCritSectEnter(&pThis->CritSect); 2998 3583 PDRVAUDIOSTREAM pStreamEx; 2999 3584 RTListForEach(&pThis->lstStreams, pStreamEx, DRVAUDIOSTREAM, ListEntry) 3000 3585 { 3001 pStreamEx->Core.fStatus |= PDMAUDIOSTREAM_STS_NEED_REINIT; 3002 PDMAUDIOSTREAM_STS_ASSERT_VALID(pStreamEx->Core.fStatus); 3003 pStreamEx->cTriesReInit = 0; 3004 pStreamEx->nsLastReInit = 0; 3586 if (pStreamEx->Core.enmDir == enmDir) 3587 { 3588 if (pThis->pHostDrvAudio->pfnStreamNotifyDeviceChanged) 3589 { 3590 LogFlowFunc(("Calling pfnStreamNotifyDeviceChanged on %s, old backend status: %#x...\n", pStreamEx->Core.szName, 3591 drvAudioStreamGetBackendStatus(pThis, pStreamEx) )); 3592 pThis->pHostDrvAudio->pfnStreamNotifyDeviceChanged(pThis->pHostDrvAudio, pStreamEx->pBackend, pvUser); 3593 LogFlowFunc(("New stream backend status: %#x.\n", drvAudioStreamGetBackendStatus(pThis, pStreamEx) )); 3594 } 3595 else 3596 drvAudioStreamMarkNeedReInit(pStreamEx, __PRETTY_FUNCTION__); 3597 } 3598 } 3599 RTCritSectLeave(&pThis->CritSect); 3600 } 3601 3602 3603 /** 3604 * @interface_method_impl{PDMIAUDIONOTIFYFROMHOST,pfnStreamNotifyDeviceChanged} 3605 */ 3606 static DECLCALLBACK(void) drvAudioNotifyFromHost_StreamNotifyDeviceChanged(PPDMIAUDIONOTIFYFROMHOST pInterface, 3607 PPDMAUDIOBACKENDSTREAM pStream, bool fReInit) 3608 { 3609 PDRVAUDIO pThis = RT_FROM_MEMBER(pInterface, DRVAUDIO, IAudioNotifyFromHost); 3610 3611 /* 3612 * Backend stream to validated DrvAudio stream: 3613 */ 3614 AssertPtrReturnVoid(pStream); 3615 AssertReturnVoid(pStream->uMagic == PDMAUDIOBACKENDSTREAM_MAGIC); 3616 PDRVAUDIOSTREAM pStreamEx = (PDRVAUDIOSTREAM)pStream->pStream; 3617 AssertPtrReturnVoid(pStreamEx); 3618 AssertReturnVoid(pStreamEx->Core.uMagic == PDMAUDIOSTREAM_MAGIC); 3619 AssertReturnVoid(pStreamEx->uMagic == DRVAUDIOSTREAM_MAGIC); 3620 3621 /* 3622 * Grab the lock and do the requested work. 3623 */ 3624 RTCritSectEnter(&pThis->CritSect); 3625 AssertReturnVoidStmt(pStreamEx->uMagic == DRVAUDIOSTREAM_MAGIC, RTCritSectLeave(&pThis->CritSect)); /* paranoia */ 3626 3627 if (fReInit) 3628 drvAudioStreamMarkNeedReInit(pStreamEx, __PRETTY_FUNCTION__); 3629 else 3630 { 3631 /* 3632 * Adjust the stream state now that the device has (perhaps finally) been switched. 3633 * 3634 * For enabled output streams, we must update the play state. We could try commit 3635 * pre-buffered data here, but it's really not worth the hazzle and risk (don't 3636 * know which thread we're on, do we now). 3637 */ 3638 AssertStmt(!(pStreamEx->Core.fStatus & PDMAUDIOSTREAM_STS_NEED_REINIT), 3639 pStreamEx->Core.fStatus &= ~PDMAUDIOSTREAM_STS_NEED_REINIT); 3640 3641 if ( pStreamEx->Core.enmDir == PDMAUDIODIR_OUT 3642 && (pStreamEx->Core.fStatus & PDMAUDIOSTREAM_STS_ENABLED)) 3643 { 3644 DRVAUDIOPLAYSTATE const enmPlayState = pStreamEx->Out.enmPlayState; 3645 pStreamEx->Out.enmPlayState = DRVAUDIOPLAYSTATE_PREBUF; 3646 LogFunc(("%s: %s -> %s\n", pStreamEx->Core.szName, 3647 drvAudioPlayStateName(enmPlayState), drvAudioPlayStateName(pStreamEx->Out.enmPlayState) )); 3648 } 3649 } 3650 3651 RTCritSectLeave(&pThis->CritSect); 3652 } 3653 3654 3655 /** 3656 * @interface_method_impl{PDMIAUDIONOTIFYFROMHOST,pfnNotifyDevicesChanged} 3657 */ 3658 static DECLCALLBACK(void) drvAudioNotifyFromHost_NotifyDevicesChanged(PPDMIAUDIONOTIFYFROMHOST pInterface) 3659 { 3660 PDRVAUDIO pThis = RT_FROM_MEMBER(pInterface, DRVAUDIO, IAudioNotifyFromHost); 3661 LogRel(("Audio: Device configuration of driver '%s' has changed\n", pThis->szName)); 3662 3663 /** @todo Remove legacy behaviour: */ 3664 if (!pThis->pHostDrvAudio->pfnStreamNotifyDeviceChanged) 3665 { 3666 /** @todo r=bird: Locking? */ 3667 /* Mark all host streams to re-initialize. */ 3668 PDRVAUDIOSTREAM pStreamEx; 3669 RTListForEach(&pThis->lstStreams, pStreamEx, DRVAUDIOSTREAM, ListEntry) 3670 { 3671 drvAudioStreamMarkNeedReInit(pStreamEx, __PRETTY_FUNCTION__); 3672 } 3005 3673 } 3006 3674 … … 3009 3677 pThis->fEnumerateDevices = true; 3010 3678 # endif 3011 }3012 3013 3014 /**3015 * @interface_method_impl{PDMIAUDIONOTIFYFROMHOST,pfnNotifyDevicesChanged}3016 */3017 static DECLCALLBACK(void) drvAudioNotifyFromHost_NotifyDevicesChanged(PPDMIAUDIONOTIFYFROMHOST pInterface)3018 {3019 PDRVAUDIO pThis = RT_FROM_MEMBER(pInterface, DRVAUDIO, IAudioNotifyFromHost);3020 3021 LogRel(("Audio: Device configuration of driver '%s' has changed\n", pThis->szName));3022 drvAudioScheduleReInitInternal(pThis);3023 3679 } 3024 3680 … … 3571 4227 pThis->IAudioConnector.pfnStreamCapture = drvAudioStreamCapture; 3572 4228 /* IAudioNotifyFromHost */ 3573 pThis->IAudioNotifyFromHost.pfnNotifyDevicesChanged = drvAudioNotifyFromHost_NotifyDevicesChanged; 4229 pThis->IAudioNotifyFromHost.pfnNotifyDeviceChanged = drvAudioNotifyFromHost_NotifyDeviceChanged; 4230 pThis->IAudioNotifyFromHost.pfnStreamNotifyDeviceChanged = drvAudioNotifyFromHost_StreamNotifyDeviceChanged; 4231 pThis->IAudioNotifyFromHost.pfnNotifyDevicesChanged = drvAudioNotifyFromHost_NotifyDevicesChanged; 3574 4232 3575 4233 /* -
trunk/src/VBox/Devices/Audio/DrvHostAudioNull.cpp
r88724 r88760 229 229 DECL_HIDDEN_CONST(PDMIHOSTAUDIO) const g_DrvHostAudioNull = 230 230 { 231 /* .pfnGetConfig =*/ drvHostNullAudioHA_GetConfig, 232 /* .pfnGetDevices =*/ NULL, 233 /* .pfnGetStatus =*/ drvHostNullAudioHA_GetStatus, 234 /* .pfnStreamConfigHint =*/ NULL, 235 /* .pfnStreamCreate =*/ drvHostNullAudioHA_StreamCreate, 236 /* .pfnStreamDestroy =*/ drvHostNullAudioHA_StreamDestroy, 237 /* .pfnStreamControl =*/ drvHostNullAudioHA_StreamControl, 238 /* .pfnStreamGetReadable =*/ drvHostNullAudioHA_StreamGetReadable, 239 /* .pfnStreamGetWritable =*/ drvHostNullAudioHA_StreamGetWritable, 240 /* .pfnStreamGetPending =*/ drvHostNullAudioHA_StreamGetPending, 241 /* .pfnStreamGetStatus =*/ drvHostNullAudioHA_StreamGetStatus, 242 /* .pfnStreamPlay =*/ drvHostNullAudioHA_StreamPlay, 243 /* .pfnStreamCapture =*/ drvHostNullAudioHA_StreamCapture, 231 /* .pfnGetConfig =*/ drvHostNullAudioHA_GetConfig, 232 /* .pfnGetDevices =*/ NULL, 233 /* .pfnGetStatus =*/ drvHostNullAudioHA_GetStatus, 234 /* .pfnStreamConfigHint =*/ NULL, 235 /* .pfnStreamCreate =*/ drvHostNullAudioHA_StreamCreate, 236 /* .pfnStreamDestroy =*/ drvHostNullAudioHA_StreamDestroy, 237 /* .pfnStreamNotifyDeviceChanged =*/ NULL, 238 /* .pfnStreamControl =*/ drvHostNullAudioHA_StreamControl, 239 /* .pfnStreamGetReadable =*/ drvHostNullAudioHA_StreamGetReadable, 240 /* .pfnStreamGetWritable =*/ drvHostNullAudioHA_StreamGetWritable, 241 /* .pfnStreamGetPending =*/ drvHostNullAudioHA_StreamGetPending, 242 /* .pfnStreamGetStatus =*/ drvHostNullAudioHA_StreamGetStatus, 243 /* .pfnStreamPlay =*/ drvHostNullAudioHA_StreamPlay, 244 /* .pfnStreamCapture =*/ drvHostNullAudioHA_StreamCapture, 244 245 }; 245 246
Note:
See TracChangeset
for help on using the changeset viewer.