Changeset 88819 in vbox for trunk/src/VBox
- Timestamp:
- May 3, 2021 10:26:28 AM (4 years ago)
- Location:
- trunk/src/VBox
- Files:
-
- 14 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Audio/DrvAudio.cpp
r88763 r88819 33 33 #include <iprt/assert.h> 34 34 #include <iprt/circbuf.h> 35 #include <iprt/req.h> 35 36 #include <iprt/string.h> 37 #include <iprt/thread.h> 36 38 #include <iprt/uuid.h> 37 39 … … 99 101 { 100 102 /** The publicly visible bit. */ 101 PDMAUDIOSTREAM Core;103 PDMAUDIOSTREAM Core; 102 104 103 105 /** Just an extra magic to verify that we allocated the stream rather than some 104 106 * faked up stuff from the device (DRVAUDIOSTREAM_MAGIC). */ 105 uintptr_t uMagic;107 uintptr_t uMagic; 106 108 107 109 /** List entry in DRVAUDIO::lstStreams. */ 108 RTLISTNODE ListEntry; 110 RTLISTNODE ListEntry; 111 112 /** Number of references to this stream. 113 * Only can be destroyed when the reference count reaches 0. */ 114 uint32_t volatile cRefs; 115 /** Stream status - PDMAUDIOSTREAM_STS_XXX. */ 116 uint32_t fStatus; 109 117 110 118 /** Data to backend-specific stream data. … … 112 120 * 113 121 * That way the backends do not have access to the audio connector's data. */ 114 PPDMAUDIOBACKENDSTREAM pBackend;122 PPDMAUDIOBACKENDSTREAM pBackend; 115 123 116 124 /** Do not use the mixing buffers (Guest::MixBuf, Host::MixBuf). */ 117 bool fNoMixBufs; 118 bool afPadding[3]; 125 bool fNoMixBufs; 126 /** Set if pfnStreamCreate returned VINF_AUDIO_STREAM_ASYNC_INIT_NEEDED. */ 127 bool fNeedAsyncInit; 128 bool afPadding[2]; 119 129 120 130 /** Number of (re-)tries while re-initializing the stream. */ 121 uint32_t cTriesReInit;131 uint32_t cTriesReInit; 122 132 123 133 /** The backend status at the last play or capture call. 124 134 * This is used to detect state changes. */ 125 uint32_t fLastBackendStatus; 135 uint32_t fLastBackendStatus; 136 137 /** The pfnStreamInitAsync request handle. */ 138 PRTREQ hReqInitAsync; 126 139 127 140 /** The guest side of the stream. */ 128 DRVAUDIOSTREAMCTX Guest;141 DRVAUDIOSTREAMCTX Guest; 129 142 /** The host side of the stream. */ 130 DRVAUDIOSTREAMCTX Host;143 DRVAUDIOSTREAMCTX Host; 131 144 132 145 133 146 /** Timestamp (in ns) since last trying to re-initialize. 134 147 * Might be 0 if has not been tried yet. */ 135 uint64_t nsLastReInit;148 uint64_t nsLastReInit; 136 149 /** Timestamp (in ns) since last iteration. */ 137 uint64_t nsLastIterated;150 uint64_t nsLastIterated; 138 151 /** Timestamp (in ns) since last playback / capture. */ 139 uint64_t nsLastPlayedCaptured;152 uint64_t nsLastPlayedCaptured; 140 153 /** Timestamp (in ns) since last read (input streams) or 141 154 * write (output streams). */ 142 uint64_t nsLastReadWritten;155 uint64_t nsLastReadWritten; 143 156 /** Internal stream position (as per pfnStreamWrite/Read). */ 144 uint64_t offInternal; 145 157 uint64_t offInternal; 146 158 147 159 /** Union for input/output specifics depending on enmDir. */ … … 275 287 PDMIAUDIOCONNECTOR IAudioConnector; 276 288 /** Interface used by the host backend. */ 277 PDMI AUDIONOTIFYFROMHOST IAudioNotifyFromHost;289 PDMIHOSTAUDIOPORT IHostAudioPort; 278 290 /** Pointer to the driver instance. */ 279 291 PPDMDRVINS pDrvIns; … … 309 321 } Out; 310 322 323 /** Request pool if the backend needs it for async stream creation. */ 324 RTREQPOOL hReqPool; 325 311 326 /** Handle to the disable-iteration timer. */ 312 327 TMTIMERHANDLE hTimer; … … 338 353 static int drvAudioStreamControlInternal(PDRVAUDIO pThis, PDRVAUDIOSTREAM pStreamEx, PDMAUDIOSTREAMCMD enmStreamCmd); 339 354 static int drvAudioStreamUninitInternal(PDRVAUDIO pThis, PDRVAUDIOSTREAM pStreamEx); 355 static uint32_t drvAudioStreamReleaseInternal(PDRVAUDIO pThis, PDRVAUDIOSTREAM pStreamEx, bool fMayDestroy); 340 356 static int drvAudioStreamIterateInternal(PDRVAUDIO pThis, PDRVAUDIOSTREAM pStreamEx); 341 357 342 343 #ifdef LOG_ENABLED344 345 358 /** Buffer size for dbgAudioStreamStatusToStr. */ 346 # define DRVAUDIO_STATUS_STR_MAX sizeof("INITIALIZED ENABLED PAUSED PENDING_DISABLED NEED_REINIT PREPARING_SWITCH 0x12345678")359 # define DRVAUDIO_STATUS_STR_MAX sizeof("INITIALIZED ENABLED PAUSED PENDING_DISABLED NEED_REINIT BACKEND_READY PREPARING_SWITCH 0x12345678") 347 360 348 361 /** … … 368 381 { RT_STR_TUPLE("PENDING_DISABLE "), PDMAUDIOSTREAM_STS_PENDING_DISABLE }, 369 382 { RT_STR_TUPLE("NEED_REINIT "), PDMAUDIOSTREAM_STS_NEED_REINIT }, 383 { RT_STR_TUPLE("BACKEND_READY "), PDMAUDIOSTREAM_STS_BACKEND_READY }, 370 384 { RT_STR_TUPLE("PREPARING_SWITCH "), PDMAUDIOSTREAM_STS_PREPARING_SWITCH }, 371 385 }; … … 393 407 } 394 408 395 #endif /* defined(LOG_ENABLED) */396 409 397 410 /** … … 426 439 DECLINLINE(uint32_t) drvAudioStreamGetBackendStatus(PDRVAUDIO pThis, PDRVAUDIOSTREAM pStreamEx) 427 440 { 428 Assert(pThis->pHostDrvAudio); 429 uint32_t fBackendStatus = pThis->pHostDrvAudio->pfnStreamGetStatus(pThis->pHostDrvAudio, pStreamEx->pBackend); 441 uint32_t fBackendStatus = pThis->pHostDrvAudio 442 ? pThis->pHostDrvAudio->pfnStreamGetStatus(pThis->pHostDrvAudio, pStreamEx->pBackend) 443 : 0; 430 444 PDMAUDIOSTREAM_STS_ASSERT_VALID_BACKEND(fBackendStatus); 431 445 return fBackendStatus; … … 518 532 PDRVAUDIO pThis = RT_FROM_MEMBER(pInterface, DRVAUDIO, IAudioConnector); 519 533 AssertPtr(pThis); 520 534 LogFlowFunc(("enmDir=%s fEnable=%d\n", PDMAudioDirGetName(enmDir), fEnable)); 535 536 /* 537 * Figure which status flag variable is being updated. 538 */ 521 539 bool *pfEnabled; 522 540 if (enmDir == PDMAUDIODIR_IN) … … 527 545 AssertFailedReturn(VERR_INVALID_PARAMETER); 528 546 547 /* 548 * Grab the driver wide lock and check it. Ignore call if no change. 549 */ 529 550 int rc = RTCritSectEnter(&pThis->CritSect); 530 551 AssertRCReturn(rc, rc); … … 535 556 fEnable ? "Enabling" : "Disabling", enmDir == PDMAUDIODIR_IN ? "input" : "output", pThis->szName)); 536 557 537 /* Update the status first, as this will be checked for in drvAudioStreamControlInternalBackend() below. */ 538 *pfEnabled = fEnable; 539 558 /* 559 * When enabling, we must update flag before calling drvAudioStreamControlInternalBackend. 560 */ 561 if (fEnable) 562 *pfEnabled = true; 563 564 /* 565 * Update the backend status for the streams in the given direction. 566 * 567 * The pThis->Out.fEnable / pThis->In.fEnable status flags only reflect in the 568 * direction of the backend, drivers and devices above us in the chain does not 569 * know about this. When disabled playback goes to /dev/null and we capture 570 * only silence. This means pStreamEx->fStatus holds the nominal status 571 * and we'll use it to restore the operation. (See also @bugref{9882}.) 572 */ 540 573 PDRVAUDIOSTREAM pStreamEx; 541 574 RTListForEach(&pThis->lstStreams, pStreamEx, DRVAUDIOSTREAM, ListEntry) 542 575 { 543 if (pStreamEx->Core.enmDir != enmDir) /* Skip unwanted streams. */ 544 continue; 545 546 /* Note: Only enable / disable the backend, do *not* change the stream's internal status. 547 * Callers (device emulation, mixer, ...) from outside will not see any status or behavior change, 548 * to not confuse the rest of the state machine. 549 * 550 * When disabling: 551 * - playing back audo data would go to /dev/null 552 * - recording audio data would return silence instead 553 * 554 * See @bugref{9882}. 555 */ 556 int rc2 = drvAudioStreamControlInternalBackend(pThis, pStreamEx, 557 fEnable ? PDMAUDIOSTREAMCMD_ENABLE : PDMAUDIOSTREAMCMD_DISABLE); 558 if (RT_FAILURE(rc2)) 576 if (pStreamEx->Core.enmDir == enmDir) 559 577 { 560 if (rc2 == VERR_AUDIO_STREAM_NOT_READY) 561 LogRel(("Audio: Stream '%s' not available\n", pStreamEx->Core.szName)); 562 else 563 LogRel(("Audio: Failed to %s %s stream '%s', rc=%Rrc\n", fEnable ? "enable" : "disable", 564 enmDir == PDMAUDIODIR_IN ? "input" : "output", pStreamEx->Core.szName, rc2)); 565 } 566 else 567 { 568 /* When (re-)enabling a stream, clear the disabled warning bit again. */ 578 /* 579 * When (re-)enabling a stream, clear the disabled warning bit again. 580 */ 569 581 if (fEnable) 570 582 pStreamEx->Core.fWarningsShown &= ~PDMAUDIOSTREAM_WARN_FLAGS_DISABLED; 583 584 /* 585 * We don't need to do anything unless the stream is enabled. 586 * Paused includes enabled, as does draining, but we only want the former. 587 */ 588 uint32_t const fStatus = pStreamEx->fStatus; 589 if (fStatus & PDMAUDIOSTREAM_STS_ENABLED) 590 { 591 const char *pszOperation; 592 int rc2; 593 if (fEnable) 594 { 595 if (!(fStatus & PDMAUDIOSTREAM_STS_PENDING_DISABLE)) 596 { 597 rc2 = drvAudioStreamControlInternalBackend(pThis, pStreamEx, PDMAUDIOSTREAMCMD_ENABLE); 598 pszOperation = "enable"; 599 if (RT_SUCCESS(rc2) && (fStatus & PDMAUDIOSTREAM_STS_PAUSED)) 600 { 601 rc2 = drvAudioStreamControlInternalBackend(pThis, pStreamEx, PDMAUDIOSTREAMCMD_PAUSE); 602 pszOperation = "pause"; 603 } 604 } 605 else 606 { 607 rc2 = VINF_SUCCESS; 608 pszOperation = NULL; 609 } 610 } 611 else 612 { 613 rc2 = drvAudioStreamControlInternalBackend(pThis, pStreamEx, PDMAUDIOSTREAMCMD_DISABLE); 614 pszOperation = "disable"; 615 } 616 if (RT_FAILURE(rc2)) 617 { 618 LogRel(("Audio: Failed to %s %s stream '%s': %Rrc\n", 619 pszOperation, enmDir == PDMAUDIODIR_IN ? "input" : "output", pStreamEx->Core.szName, rc2)); 620 if (RT_SUCCESS(rc)) 621 rc = rc2; /** @todo r=bird: This isn't entirely helpful to the caller since we'll update the status 622 * regardless of the status code we return. And anyway, there is nothing that can be done 623 * about individual stream by the caller... */ 624 } 625 } 571 626 } 572 573 if (RT_SUCCESS(rc)) 574 rc = rc2; 575 576 /* Keep going. */ 577 } 627 } 628 629 /* 630 * When disabling, we must update the status flag after the 631 * drvAudioStreamControlInternalBackend(DISABLE) calls. 632 */ 633 *pfEnabled = fEnable; 578 634 } 579 635 … … 840 896 * @interface_method_impl{PDMIAUDIOCONNECTOR,pfnStreamConfigHint} 841 897 */ 898 static DECLCALLBACK(void) drvAudioStreamConfigHintWorker(PPDMIHOSTAUDIO pHostDrvAudio, PPDMAUDIOSTREAMCFG pCfg) 899 { 900 LogFlowFunc(("pHostDrvAudio=%p pCfg=%p\n", pHostDrvAudio, pCfg)); 901 AssertPtrReturnVoid(pCfg); 902 AssertPtrReturnVoid(pHostDrvAudio); 903 AssertPtrReturnVoid(pHostDrvAudio->pfnStreamConfigHint); 904 905 pHostDrvAudio->pfnStreamConfigHint(pHostDrvAudio, pCfg); 906 PDMAudioStrmCfgFree(pCfg); 907 LogFlowFunc(("returns\n")); 908 } 909 910 911 /** 912 * @interface_method_impl{PDMIAUDIOCONNECTOR,pfnStreamConfigHint} 913 */ 842 914 static DECLCALLBACK(void) drvAudioStreamConfigHint(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAMCFG pCfg) 843 915 { … … 863 935 AssertLogRelRC(rc); 864 936 if (RT_SUCCESS(rc)) 865 pThis->pHostDrvAudio->pfnStreamConfigHint(pThis->pHostDrvAudio, pCfg); 937 { 938 rc = VERR_CALLBACK_RETURN; 939 if (pThis->BackendCfg.fFlags & PDMAUDIOBACKEND_F_ASYNC_HINT) 940 { 941 PPDMAUDIOSTREAMCFG pDupCfg = PDMAudioStrmCfgDup(pCfg); 942 if (pDupCfg) 943 { 944 rc = RTReqPoolCallVoidNoWait(pThis->hReqPool, (PFNRT)drvAudioStreamConfigHintWorker, 945 2, pThis->pHostDrvAudio, pDupCfg); 946 if (RT_SUCCESS(rc)) 947 LogFlowFunc(("Asynchronous call running on worker thread.\n")); 948 else 949 PDMAudioStrmCfgFree(pDupCfg); 950 } 951 } 952 if (RT_FAILURE_NP(rc)) 953 { 954 LogFlowFunc(("Doing synchronous call...\n")); 955 pThis->pHostDrvAudio->pfnStreamConfigHint(pThis->pHostDrvAudio, pCfg); 956 } 957 } 866 958 } 867 959 else … … 872 964 873 965 RTCritSectLeave(&pThis->CritSect); 966 } 967 968 969 /** 970 * For performing PDMIHOSTAUDIO::pfnStreamInitAsync on a worker thread. 971 * 972 * @param pThis Pointer to the DrvAudio instance data. 973 * @param pStreamEx The stream. One reference for us to release. 974 */ 975 static DECLCALLBACK(void) drvAudioStreamInitAsync(PDRVAUDIO pThis, PDRVAUDIOSTREAM pStreamEx) 976 { 977 LogFlow(("pThis=%p pStreamEx=%p (%s)\n", pThis, pStreamEx->Core.szName)); 978 979 /* 980 * Do the init job. 981 * 982 * This critsect entering and leaving here isn't really necessary, 983 * but well, I'm a bit paranoid, so sue me. 984 */ 985 RTCritSectEnter(&pThis->CritSect); 986 PPDMIHOSTAUDIO pIHostDrvAudio = pThis->pHostDrvAudio; 987 RTCritSectLeave(&pThis->CritSect); 988 AssertPtr(pIHostDrvAudio); 989 int rc; 990 bool fDestroyed; 991 if (pIHostDrvAudio && pIHostDrvAudio->pfnStreamInitAsync) 992 { 993 fDestroyed = pStreamEx->cRefs <= 1; 994 rc = pIHostDrvAudio->pfnStreamInitAsync(pIHostDrvAudio, pStreamEx->pBackend, fDestroyed); 995 LogFlow(("pfnStreamInitAsync returns %Rrc (on %p, fDestroyed=%d)\n", rc, pStreamEx, fDestroyed)); 996 } 997 else 998 { 999 fDestroyed = true; 1000 rc = VERR_AUDIO_STREAM_COULD_NOT_CREATE; 1001 } 1002 1003 /* 1004 * On success, update the backend on the stream status and mark it ready for business. 1005 */ 1006 RTCritSectEnter(&pThis->CritSect); 1007 if (RT_SUCCESS(rc) && !fDestroyed) 1008 { 1009 1010 /* 1011 * Update the backend state. 1012 */ 1013 pStreamEx->fStatus |= PDMAUDIOSTREAM_STS_BACKEND_READY; /* before the backend control call! */ 1014 1015 if (pStreamEx->fStatus & PDMAUDIOSTREAM_STS_ENABLED) 1016 { 1017 rc = drvAudioStreamControlInternalBackend(pThis, pStreamEx, PDMAUDIOSTREAMCMD_ENABLE); 1018 if (RT_SUCCESS(rc)) 1019 { 1020 if (pStreamEx->fStatus & PDMAUDIOSTREAM_STS_PAUSED) 1021 { 1022 rc = drvAudioStreamControlInternalBackend(pThis, pStreamEx, PDMAUDIOSTREAMCMD_PAUSE); 1023 if (RT_FAILURE(rc)) 1024 LogRelMax(64, ("Audio: Failed to pause stream '%s' after initialization completed: %Rrc\n", 1025 pStreamEx->Core.szName, rc)); 1026 } 1027 } 1028 else 1029 LogRelMax(64, ("Audio: Failed to enable stream '%s' after initialization completed: %Rrc\n", 1030 pStreamEx->Core.szName, rc)); 1031 } 1032 1033 /* 1034 * Modify the play state if output stream. 1035 */ 1036 if (pStreamEx->Core.enmDir == PDMAUDIODIR_OUT) 1037 { 1038 DRVAUDIOPLAYSTATE const enmPlayState = pStreamEx->Out.enmPlayState; 1039 switch (enmPlayState) 1040 { 1041 case DRVAUDIOPLAYSTATE_PREBUF: 1042 case DRVAUDIOPLAYSTATE_PREBUF_SWITCHING: 1043 break; 1044 case DRVAUDIOPLAYSTATE_PREBUF_OVERDUE: 1045 pStreamEx->Out.enmPlayState = DRVAUDIOPLAYSTATE_PREBUF_COMMITTING; 1046 break; 1047 case DRVAUDIOPLAYSTATE_NOPLAY: 1048 pStreamEx->Out.enmPlayState = DRVAUDIOPLAYSTATE_PREBUF; 1049 break; 1050 case DRVAUDIOPLAYSTATE_PLAY: 1051 case DRVAUDIOPLAYSTATE_PLAY_PREBUF: 1052 case DRVAUDIOPLAYSTATE_PREBUF_COMMITTING: 1053 AssertFailedBreak(); 1054 /* no default */ 1055 case DRVAUDIOPLAYSTATE_END: 1056 case DRVAUDIOPLAYSTATE_INVALID: 1057 break; 1058 } 1059 LogFunc(("enmPlayState: %s -> %s\n", drvAudioPlayStateName(enmPlayState), 1060 drvAudioPlayStateName(pStreamEx->Out.enmPlayState) )); 1061 } 1062 1063 /* 1064 * Tweak the last backend status to asserting in 1065 * drvAudioStreamPlayProcessBackendStateChange(). 1066 */ 1067 pStreamEx->fLastBackendStatus |= drvAudioStreamGetBackendStatus(pThis, pStreamEx) 1068 & PDMAUDIOSTREAM_STS_INITIALIZED; 1069 } 1070 /* 1071 * Don't quite know what to do on failure... 1072 */ 1073 else if (!fDestroyed) 1074 { 1075 LogRelMax(64, ("Audio: Failed to initialize stream '%s': %Rrc\n", pStreamEx->Core.szName, rc)); 1076 } 1077 1078 /* 1079 * Release the request handle, must be done while inside the critical section. 1080 */ 1081 if (pStreamEx->hReqInitAsync != NIL_RTREQ) 1082 { 1083 LogFlowFunc(("Releasing hReqInitAsync=%p\n", pStreamEx->hReqInitAsync)); 1084 RTReqRelease(pStreamEx->hReqInitAsync); 1085 pStreamEx->hReqInitAsync = NIL_RTREQ; 1086 } 1087 1088 RTCritSectLeave(&pThis->CritSect); 1089 1090 /* 1091 * Release our stream reference. 1092 */ 1093 uint32_t cRefs = drvAudioStreamReleaseInternal(pThis, pStreamEx, true /*fMayDestroy*/); 1094 LogFlowFunc(("returns (fDestroyed=%d, cRefs=%u)\n", fDestroyed, cRefs)); RT_NOREF(cRefs); 874 1095 } 875 1096 … … 896 1117 PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq) 897 1118 { 898 AssertMsg((pStreamEx-> Core.fStatus & PDMAUDIOSTREAM_STS_INITIALIZED) == 0,1119 AssertMsg((pStreamEx->fStatus & PDMAUDIOSTREAM_STS_INITIALIZED) == 0, 899 1120 ("Stream '%s' already initialized in backend\n", pStreamEx->Core.szName)); 900 1121 … … 922 1143 * Call the host driver to create the stream. 923 1144 */ 924 AssertPtr(pThis->pHostDrvAudio); 925 if (pThis->pHostDrvAudio) 926 rc = pThis->pHostDrvAudio->pfnStreamCreate(pThis->pHostDrvAudio, pStreamEx->pBackend, pCfgReq, pCfgAcq); 1145 AssertLogRelMsgReturn(RT_VALID_PTR(pThis->pHostDrvAudio), ("Audio: %p\n", pThis->pHostDrvAudio), VERR_PDM_NO_ATTACHED_DRIVER); 1146 rc = pThis->pHostDrvAudio->pfnStreamCreate(pThis->pHostDrvAudio, pStreamEx->pBackend, pCfgReq, pCfgAcq); 1147 if (RT_SUCCESS(rc)) 1148 { 1149 AssertLogRelReturn(pStreamEx->pBackend->uMagic == PDMAUDIOBACKENDSTREAM_MAGIC, VERR_INTERNAL_ERROR_3); 1150 AssertLogRelReturn(pStreamEx->pBackend->pStream == &pStreamEx->Core, VERR_INTERNAL_ERROR_3); 1151 1152 /* Must set the backend-initialized flag now or the backend won't be 1153 destroyed (this used to be done at the end of this function, with 1154 several possible early return paths before it). */ 1155 pStreamEx->fStatus |= PDMAUDIOSTREAM_STS_INITIALIZED; 1156 1157 pStreamEx->fLastBackendStatus = drvAudioStreamGetBackendStatus(pThis, pStreamEx); 1158 PDMAUDIOSTREAM_STS_ASSERT_VALID(pStreamEx->fStatus); 1159 } 927 1160 else 928 rc = VERR_PDM_NO_ATTACHED_DRIVER;929 if (RT_FAILURE(rc))930 1161 { 931 1162 if (rc == VERR_NOT_SUPPORTED) … … 937 1168 return rc; 938 1169 } 939 AssertLogRelReturn(pStreamEx->pBackend->uMagic == PDMAUDIOBACKENDSTREAM_MAGIC, VERR_INTERNAL_ERROR_3); 940 AssertLogRelReturn(pStreamEx->pBackend->pStream == &pStreamEx->Core, VERR_INTERNAL_ERROR_3); 1170 1171 /* Remember if we need to call pfnStreamInitAsync. */ 1172 pStreamEx->fNeedAsyncInit = rc == VINF_AUDIO_STREAM_ASYNC_INIT_NEEDED; 1173 AssertStmt(rc != VINF_AUDIO_STREAM_ASYNC_INIT_NEEDED || pThis->pHostDrvAudio->pfnStreamInitAsync != NULL, 1174 pStreamEx->fNeedAsyncInit = false); 1175 Assert(rc != VINF_AUDIO_STREAM_ASYNC_INIT_NEEDED || !(pStreamEx->fLastBackendStatus & PDMAUDIOSTREAM_STS_INITIALIZED)); 941 1176 942 1177 /* Validate acquired configuration. */ … … 983 1218 ("Acquired pre-buffering size must be smaller or as big as the buffer size\n"), 984 1219 VERR_INVALID_PARAMETER); 985 986 pStreamEx->fLastBackendStatus = drvAudioStreamGetBackendStatus(pThis, pStreamEx);987 pStreamEx->Core.fStatus |= PDMAUDIOSTREAM_STS_INITIALIZED;988 PDMAUDIOSTREAM_STS_ASSERT_VALID(pStreamEx->Core.fStatus);989 1220 990 1221 return VINF_SUCCESS; … … 1295 1526 if (pStreamEx) 1296 1527 { 1297 /* Retrieve host driver name for easier identification. */1528 /* Make a unqiue stream name including the host (backend) driver name. */ 1298 1529 AssertPtr(pThis->pHostDrvAudio); 1299 RTStrPrintf(pStreamEx->Core.szName, RT_ELEMENTS(pStreamEx->Core.szName), "[%s] %s", 1300 pThis->BackendCfg.szName, pCfgHost->szName[0] != '\0' ? pCfgHost->szName : "<Untitled>"); 1530 size_t cchName = RTStrPrintf(pStreamEx->Core.szName, RT_ELEMENTS(pStreamEx->Core.szName), "[%s] %s:0", 1531 pThis->BackendCfg.szName, pCfgHost->szName[0] != '\0' ? pCfgHost->szName : "<Untitled>"); 1532 if (cchName < sizeof(pStreamEx->Core.szName)) 1533 { 1534 for (uint32_t i = 0; i < 256; i++) 1535 { 1536 bool fDone = true; 1537 PDRVAUDIOSTREAM pIt; 1538 RTListForEach(&pThis->lstStreams, pIt, DRVAUDIOSTREAM, ListEntry) 1539 { 1540 if (strcmp(pIt->Core.szName, pStreamEx->Core.szName) == 0) 1541 { 1542 RTStrPrintf(pStreamEx->Core.szName, RT_ELEMENTS(pStreamEx->Core.szName), "[%s] %s:%u", 1543 pThis->BackendCfg.szName, pCfgHost->szName[0] != '\0' ? pCfgHost->szName : "<Untitled>", 1544 i); 1545 fDone = false; 1546 break; 1547 } 1548 } 1549 if (fDone) 1550 break; 1551 } 1552 } 1301 1553 1302 1554 PPDMAUDIOBACKENDSTREAM pBackend = (PPDMAUDIOBACKENDSTREAM)(pStreamEx + 1); … … 1307 1559 pStreamEx->Core.cbBackend = (uint32_t)cbHstStrm; 1308 1560 pStreamEx->fNoMixBufs = RT_BOOL(fFlags & PDMAUDIOSTREAM_CREATE_F_NO_MIXBUF); 1561 pStreamEx->hReqInitAsync = NIL_RTREQ; 1309 1562 pStreamEx->uMagic = DRVAUDIOSTREAM_MAGIC; 1310 1563 … … 1316 1569 { 1317 1570 /* Set initial reference counts. */ 1318 pStreamEx-> Core.cRefs =1;1571 pStreamEx->cRefs = pStreamEx->fNeedAsyncInit ? 2 : 1; 1319 1572 1320 1573 /* Decrement the free stream counter. */ … … 1352 1605 } 1353 1606 } 1607 1608 /* 1609 * Kick off the asynchronous init. 1610 */ 1611 if (!pStreamEx->fNeedAsyncInit) 1612 { 1613 pStreamEx->fStatus |= PDMAUDIOSTREAM_STS_BACKEND_READY; 1614 PDMAUDIOSTREAM_STS_ASSERT_VALID(pStreamEx->fStatus); 1615 } 1616 else 1617 { 1618 int rc2 = RTReqPoolCallEx(pThis->hReqPool, 0 /*cMillies*/, &pStreamEx->hReqInitAsync, 1619 RTREQFLAGS_VOID | RTREQFLAGS_NO_WAIT, 1620 (PFNRT)drvAudioStreamInitAsync, 2, pThis, pStreamEx); 1621 LogFlowFunc(("hReqInitAsync=%p rc2=%Rrc\n", pStreamEx->hReqInitAsync, rc2)); 1622 AssertRCStmt(rc2, drvAudioStreamInitAsync(pThis, pStreamEx)); 1623 } 1354 1624 } 1355 1625 else … … 1391 1661 char szStreamSts[DRVAUDIO_STATUS_STR_MAX]; 1392 1662 #endif 1393 LogFunc(("[%s] fStatus=%s\n", pStreamEx->Core.szName, dbgAudioStreamStatusToStr(szStreamSts, pStreamEx-> Core.fStatus)));1394 1395 if (pStreamEx-> Core.fStatus & PDMAUDIOSTREAM_STS_INITIALIZED)1663 LogFunc(("[%s] fStatus=%s\n", pStreamEx->Core.szName, dbgAudioStreamStatusToStr(szStreamSts, pStreamEx->fStatus))); 1664 1665 if (pStreamEx->fStatus & PDMAUDIOSTREAM_STS_INITIALIZED) 1396 1666 { 1397 1667 AssertPtr(pStreamEx->pBackend); … … 1402 1672 rc = pThis->pHostDrvAudio->pfnStreamDestroy(pThis->pHostDrvAudio, pStreamEx->pBackend); 1403 1673 1404 pStreamEx-> Core.fStatus &= ~PDMAUDIOSTREAM_STS_INITIALIZED;1405 PDMAUDIOSTREAM_STS_ASSERT_VALID(pStreamEx-> Core.fStatus);1674 pStreamEx->fStatus &= ~(PDMAUDIOSTREAM_STS_INITIALIZED | PDMAUDIOSTREAM_STS_BACKEND_READY); 1675 PDMAUDIOSTREAM_STS_ASSERT_VALID(pStreamEx->fStatus); 1406 1676 } 1407 1677 … … 1424 1694 { 1425 1695 AssertPtrReturn(pThis, VERR_INVALID_POINTER); 1426 AssertMsgReturn(pStreamEx-> Core.cRefs <= 1,1427 ("Stream '%s' still has %RU32 references held when uninitializing\n", pStreamEx->Core.szName, pStreamEx-> Core.cRefs),1696 AssertMsgReturn(pStreamEx->cRefs <= 1, 1697 ("Stream '%s' still has %RU32 references held when uninitializing\n", pStreamEx->Core.szName, pStreamEx->cRefs), 1428 1698 VERR_WRONG_ORDER); 1429 LogFlowFunc(("[%s] cRefs=%RU32\n", pStreamEx->Core.szName, pStreamEx-> Core.cRefs));1699 LogFlowFunc(("[%s] cRefs=%RU32\n", pStreamEx->Core.szName, pStreamEx->cRefs)); 1430 1700 1431 1701 /* … … 1454 1724 { 1455 1725 #ifdef LOG_ENABLED 1456 if (pStreamEx-> Core.fStatus != PDMAUDIOSTREAM_STS_NONE)1726 if (pStreamEx->fStatus != PDMAUDIOSTREAM_STS_NONE) 1457 1727 { 1458 1728 char szStreamSts[DRVAUDIO_STATUS_STR_MAX]; 1459 1729 LogFunc(("[%s] Warning: Still has %s set when uninitializing\n", 1460 pStreamEx->Core.szName, dbgAudioStreamStatusToStr(szStreamSts, pStreamEx-> Core.fStatus)));1730 pStreamEx->Core.szName, dbgAudioStreamStatusToStr(szStreamSts, pStreamEx->fStatus))); 1461 1731 } 1462 1732 #endif 1463 pStreamEx-> Core.fStatus = PDMAUDIOSTREAM_STS_NONE;1733 pStreamEx->fStatus = PDMAUDIOSTREAM_STS_NONE; 1464 1734 } 1465 1735 … … 1496 1766 1497 1767 /** 1498 * @interface_method_impl{PDMIAUDIOCONNECTOR,pfnStreamDestroy} 1499 */ 1500 static DECLCALLBACK(int) drvAudioStreamDestroy(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream) 1501 { 1502 PDRVAUDIO pThis = RT_FROM_MEMBER(pInterface, DRVAUDIO, IAudioConnector); 1503 AssertPtr(pThis); 1504 1505 if (!pStream) 1506 return VINF_SUCCESS; 1507 AssertPtrReturn(pStream, VERR_INVALID_POINTER); 1508 PDRVAUDIOSTREAM pStreamEx = (PDRVAUDIOSTREAM)pStream; /* Note! Do not touch pStream after this! */ 1509 Assert(pStreamEx->Core.uMagic == PDMAUDIOSTREAM_MAGIC); 1510 Assert(pStreamEx->uMagic == DRVAUDIOSTREAM_MAGIC); 1511 Assert(pStreamEx->pBackend && pStreamEx->pBackend->uMagic == PDMAUDIOBACKENDSTREAM_MAGIC); 1512 1513 int rc = RTCritSectEnter(&pThis->CritSect); 1514 AssertRCReturn(rc, rc); 1515 1516 LogRel2(("Audio: Destroying stream '%s'\n", pStreamEx->Core.szName)); 1517 1518 LogFlowFunc(("[%s] cRefs=%RU32\n", pStreamEx->Core.szName, pStreamEx->Core.cRefs)); 1519 AssertMsg(pStreamEx->Core.cRefs <= 1, ("%u %s\n", pStreamEx->Core.cRefs, pStreamEx->Core.szName)); 1520 if (pStreamEx->Core.cRefs <= 1) 1521 { 1768 * Internal release function. 1769 * 1770 * @returns New reference count, UINT32_MAX if bad stream. 1771 * @param pThis Pointer to the DrvAudio instance data. 1772 * @param pStreamEx The stream to reference. 1773 * @param fMayDestroy Whether the caller is allowed to implicitly destroy 1774 * the stream or not. 1775 */ 1776 static uint32_t drvAudioStreamReleaseInternal(PDRVAUDIO pThis, PDRVAUDIOSTREAM pStreamEx, bool fMayDestroy) 1777 { 1778 AssertPtrReturn(pStreamEx, UINT32_MAX); 1779 AssertReturn(pStreamEx->Core.uMagic == PDMAUDIOSTREAM_MAGIC, UINT32_MAX); 1780 AssertReturn(pStreamEx->uMagic == DRVAUDIOSTREAM_MAGIC, UINT32_MAX); 1781 1782 uint32_t cRefs = ASMAtomicDecU32(&pStreamEx->cRefs); 1783 if (cRefs != 0) 1784 Assert(cRefs < _1K); 1785 else if (fMayDestroy) 1786 { 1787 /** @todo r=bird: Caching one stream in each direction for some time, 1788 * depending on the time it took to create it. drvAudioStreamCreate can use it 1789 * if the configuration matches, otherwise it'll throw it away. This will 1790 * provide a general speedup independ of device (HDA used to do this, but 1791 * doesn't) and backend implementation. Ofc, the backend probably needs an 1792 * opt-out here. */ 1793 int rc = RTCritSectEnter(&pThis->CritSect); 1794 AssertRC(rc); 1795 1522 1796 rc = drvAudioStreamUninitInternal(pThis, pStreamEx); 1523 1797 if (RT_SUCCESS(rc)) … … 1531 1805 1532 1806 drvAudioStreamFree(pStreamEx); 1533 pStreamEx = NULL;1534 pStream = NULL;1535 1807 } 1536 1808 else 1809 { 1537 1810 LogRel(("Audio: Uninitializing stream '%s' failed with %Rrc\n", pStreamEx->Core.szName, rc)); 1811 /** @todo r=bird: What's the plan now? */ 1812 } 1813 1814 RTCritSectLeave(&pThis->CritSect); 1538 1815 } 1539 1816 else 1540 rc = VERR_WRONG_ORDER; 1817 { 1818 cRefs = ASMAtomicIncU32(&pStreamEx->cRefs); 1819 AssertFailed(); 1820 } 1821 1822 Log12Func(("returns %u (%s)\n", cRefs, cRefs > 0 ? pStreamEx->Core.szName : "destroyed")); 1823 return cRefs; 1824 } 1825 1826 1827 /** 1828 * @interface_method_impl{PDMIAUDIOCONNECTOR,pfnStreamDestroy} 1829 */ 1830 static DECLCALLBACK(int) drvAudioStreamDestroy(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream) 1831 { 1832 PDRVAUDIO pThis = RT_FROM_MEMBER(pInterface, DRVAUDIO, IAudioConnector); 1833 AssertPtr(pThis); 1834 1835 /* Ignore NULL streams. */ 1836 if (!pStream) 1837 return VINF_SUCCESS; 1838 1839 PDRVAUDIOSTREAM pStreamEx = (PDRVAUDIOSTREAM)pStream; /* Note! Do not touch pStream after this! */ 1840 AssertPtrReturn(pStreamEx, VERR_INVALID_POINTER); 1841 LogFlowFunc(("ENTER - %p %s\n", pStreamEx, pStreamEx->Core.szName)); 1842 AssertReturn(pStreamEx->Core.uMagic == PDMAUDIOSTREAM_MAGIC, VERR_INVALID_MAGIC); 1843 AssertReturn(pStreamEx->uMagic == DRVAUDIOSTREAM_MAGIC, VERR_INVALID_MAGIC); 1844 AssertReturn(pStreamEx->pBackend && pStreamEx->pBackend->uMagic == PDMAUDIOBACKENDSTREAM_MAGIC, VERR_INVALID_MAGIC); 1845 1846 /* 1847 * The main difference from a regular release is that this will disable 1848 * (or drain if we could) the stream and we can cancel any pending 1849 * pfnStreamInitAsync call. 1850 */ 1851 int rc = RTCritSectEnter(&pThis->CritSect); 1852 AssertRCReturn(rc, rc); 1853 1854 if (pStreamEx->uMagic == DRVAUDIOSTREAM_MAGIC) 1855 { 1856 if (pStreamEx->cRefs > 0 && pStreamEx->cRefs < UINT32_MAX / 4) 1857 { 1858 char szStatus[DRVAUDIO_STATUS_STR_MAX], szBackendStatus[DRVAUDIO_STATUS_STR_MAX]; 1859 LogRel2(("Audio: Destroying stream '%s': cRefs=%u; status: %s; backend: %s; hReqInitAsync=%p\n", 1860 pStreamEx->Core.szName, pStreamEx->cRefs, dbgAudioStreamStatusToStr(szStatus, pStreamEx->fStatus), 1861 dbgAudioStreamStatusToStr(szBackendStatus, drvAudioStreamGetBackendStatus(pThis, pStreamEx)), 1862 pStreamEx->hReqInitAsync)); 1863 1864 /* Try cancel pending async init request and release the it. */ 1865 if (pStreamEx->hReqInitAsync != NIL_RTREQ) 1866 { 1867 Assert(pStreamEx->cRefs >= 2); 1868 int rc2 = RTReqCancel(pStreamEx->hReqInitAsync); 1869 if (RT_SUCCESS(rc2)) 1870 { 1871 LogFlowFunc(("Successfully cancelled pending pfnStreamInitAsync call (hReqInitAsync=%p).\n", 1872 pStreamEx->hReqInitAsync)); 1873 drvAudioStreamReleaseInternal(pThis, pStreamEx, true /*fMayDestroy*/); 1874 } 1875 else 1876 { 1877 LogFlowFunc(("Failed to cancel pending pfnStreamInitAsync call (hReqInitAsync=%p): %Rrc\n", 1878 pStreamEx->hReqInitAsync, rc2)); 1879 Assert(rc2 == VERR_RT_REQUEST_STATE); 1880 } 1881 1882 RTReqRelease(pStreamEx->hReqInitAsync); 1883 pStreamEx->hReqInitAsync = NIL_RTREQ; 1884 } 1885 1886 /* We don't really care about the status here as we'll release a reference regardless of the state. */ 1887 /** @todo can we somehow drain it instead? */ 1888 int rc2 = drvAudioStreamControlInternal(pThis, pStreamEx, PDMAUDIOSTREAMCMD_DISABLE); 1889 AssertRC(rc2); 1890 1891 drvAudioStreamReleaseInternal(pThis, pStreamEx, true /*fMayDestroy*/); 1892 } 1893 else 1894 AssertLogRelMsgFailedStmt(("%p cRefs=%#x\n", pStreamEx, pStreamEx->cRefs), rc = VERR_CALLER_NO_REFERENCE); 1895 } 1896 else 1897 AssertLogRelMsgFailedStmt(("%p uMagic=%#x\n", pStreamEx, pStreamEx->uMagic), rc = VERR_INVALID_MAGIC); 1541 1898 1542 1899 RTCritSectLeave(&pThis->CritSect); … … 1600 1957 * Gather current stream status. 1601 1958 */ 1602 const bool fIsEnabled = RT_BOOL(pStreamEx-> Core.fStatus & PDMAUDIOSTREAM_STS_ENABLED); /* Stream is enabled? */1959 const bool fIsEnabled = RT_BOOL(pStreamEx->fStatus & PDMAUDIOSTREAM_STS_ENABLED); /* Stream is enabled? */ 1603 1960 1604 1961 /** @todo r=bird: this is retried a bit too indiscriminately for my taste ... */ … … 1625 1982 } 1626 1983 1984 /** @todo r=bird: Why do we do the dropping and re-enabling of the stream 1985 * regardless of how the above went? It'll overwrite any above 1986 * failures for starters... */ 1627 1987 /* Drop all old data. */ 1628 1988 drvAudioStreamDropInternal(pStreamEx); … … 1631 1991 * Restore previous stream state. 1632 1992 */ 1993 /** @todo this isn't taking PAUSED or PENDING_DISABLE into consideration. */ 1633 1994 if (fIsEnabled) 1634 1995 rc = drvAudioStreamControlInternalBackend(pThis, pStreamEx, PDMAUDIOSTREAMCMD_ENABLE); … … 1652 2013 AssertReturn(pStreamEx->Core.uMagic == PDMAUDIOSTREAM_MAGIC, VERR_INVALID_MAGIC); 1653 2014 AssertReturn(pStreamEx->uMagic == DRVAUDIOSTREAM_MAGIC, VERR_INVALID_MAGIC); 1654 AssertReturn(pStreamEx-> Core.fStatus & PDMAUDIOSTREAM_STS_NEED_REINIT, VERR_INVALID_STATE);2015 AssertReturn(pStreamEx->fStatus & PDMAUDIOSTREAM_STS_NEED_REINIT, VERR_INVALID_STATE); 1655 2016 LogFlowFunc(("\n")); 1656 2017 … … 1658 2019 AssertRCReturn(rc, rc); 1659 2020 1660 if (pStreamEx-> Core.fStatus & PDMAUDIOSTREAM_STS_NEED_REINIT)2021 if (pStreamEx->fStatus & PDMAUDIOSTREAM_STS_NEED_REINIT) 1661 2022 { 1662 2023 const unsigned cMaxTries = 3; /** @todo Make this configurable? */ 1663 2024 const uint64_t tsNowNs = RTTimeNanoTS(); 2025 2026 /** @todo r=bird: Must postpone if hReqInitAsync isn't NIL or cancellable. */ 1664 2027 1665 2028 /* Throttle re-initializing streams on failure. */ … … 1691 2054 { 1692 2055 /* Remove the pending re-init flag on success. */ 1693 pStreamEx-> Core.fStatus &= ~PDMAUDIOSTREAM_STS_NEED_REINIT;1694 PDMAUDIOSTREAM_STS_ASSERT_VALID(pStreamEx-> Core.fStatus);2056 pStreamEx->fStatus &= ~PDMAUDIOSTREAM_STS_NEED_REINIT; 2057 PDMAUDIOSTREAM_STS_ASSERT_VALID(pStreamEx->fStatus); 1695 2058 } 1696 2059 else … … 1712 2075 /* Don't try to re-initialize anymore and mark as disabled. */ 1713 2076 /** @todo should mark it as not-initialized too, shouldn't we? */ 1714 pStreamEx-> Core.fStatus &= ~(PDMAUDIOSTREAM_STS_NEED_REINIT | PDMAUDIOSTREAM_STS_ENABLED);1715 PDMAUDIOSTREAM_STS_ASSERT_VALID(pStreamEx-> Core.fStatus);2077 pStreamEx->fStatus &= ~(PDMAUDIOSTREAM_STS_NEED_REINIT | PDMAUDIOSTREAM_STS_ENABLED); 2078 PDMAUDIOSTREAM_STS_ASSERT_VALID(pStreamEx->fStatus); 1716 2079 1717 2080 /* Note: Further writes to this stream go to / will be read from the bit bucket (/dev/null) from now on. */ … … 1722 2085 char szStreamSts[DRVAUDIO_STATUS_STR_MAX]; 1723 2086 #endif 1724 Log3Func(("[%s] fStatus=%s\n", pStreamEx->Core.szName, dbgAudioStreamStatusToStr(szStreamSts, pStreamEx-> Core.fStatus)));2087 Log3Func(("[%s] fStatus=%s\n", pStreamEx->Core.szName, dbgAudioStreamStatusToStr(szStreamSts, pStreamEx->fStatus))); 1725 2088 } 1726 2089 else … … 1737 2100 1738 2101 /** 2102 * Internal retain function. 2103 * 2104 * @returns New reference count, UINT32_MAX if bad stream. 2105 * @param pStreamEx The stream to reference. 2106 */ 2107 static uint32_t drvAudioStreamRetainInternal(PDRVAUDIOSTREAM pStreamEx) 2108 { 2109 AssertPtrReturn(pStreamEx, UINT32_MAX); 2110 AssertReturn(pStreamEx->Core.uMagic == PDMAUDIOSTREAM_MAGIC, UINT32_MAX); 2111 AssertReturn(pStreamEx->uMagic == DRVAUDIOSTREAM_MAGIC, UINT32_MAX); 2112 2113 uint32_t const cRefs = ASMAtomicIncU32(&pStreamEx->cRefs); 2114 Assert(cRefs > 1); 2115 Assert(cRefs < _1K); 2116 2117 Log12Func(("returns %u (%s)\n", cRefs, pStreamEx->Core.szName)); 2118 return cRefs; 2119 } 2120 2121 2122 /** 1739 2123 * @interface_method_impl{PDMIAUDIOCONNECTOR,pfnStreamRetain} 1740 2124 */ 1741 2125 static DECLCALLBACK(uint32_t) drvAudioStreamRetain(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream) 1742 2126 { 1743 AssertPtrReturn(pInterface, UINT32_MAX); 1744 AssertPtrReturn(pStream, UINT32_MAX); 1745 AssertReturn(pStream->uMagic == PDMAUDIOSTREAM_MAGIC, UINT32_MAX); 1746 AssertReturn(((PDRVAUDIOSTREAM)pStream)->uMagic == DRVAUDIOSTREAM_MAGIC, UINT32_MAX); 1747 RT_NOREF(pInterface); 1748 1749 uint32_t const cRefs = ASMAtomicIncU32(&pStream->cRefs); 1750 Assert(cRefs > 1); 1751 Assert(cRefs < _1K); 1752 1753 return cRefs; 2127 RT_NOREF(pInterface); 2128 return drvAudioStreamRetainInternal((PDRVAUDIOSTREAM)pStream); 1754 2129 } 1755 2130 … … 1760 2135 static DECLCALLBACK(uint32_t) drvAudioStreamRelease(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream) 1761 2136 { 1762 AssertPtrReturn(pInterface, UINT32_MAX); 1763 AssertPtrReturn(pStream, UINT32_MAX); 1764 AssertReturn(pStream->uMagic == PDMAUDIOSTREAM_MAGIC, UINT32_MAX); 1765 AssertReturn(((PDRVAUDIOSTREAM)pStream)->uMagic == DRVAUDIOSTREAM_MAGIC, UINT32_MAX); 1766 RT_NOREF(pInterface); 1767 1768 uint32_t cRefs = ASMAtomicDecU32(&pStream->cRefs); 1769 AssertStmt(cRefs >= 1, cRefs = ASMAtomicIncU32(&pStream->cRefs)); 1770 Assert(cRefs < _1K); 1771 1772 return cRefs; 2137 return drvAudioStreamReleaseInternal(RT_FROM_MEMBER(pInterface, DRVAUDIO, IAudioConnector), 2138 (PDRVAUDIOSTREAM)pStream, 2139 false /*fMayDestroy*/); 1773 2140 } 1774 2141 … … 1776 2143 /** 1777 2144 * Controls a stream's backend. 1778 *1779 * If the stream has no backend available, VERR_NOT_FOUND is returned1780 * (bird: actually the code returns VINF_SUCCESS).1781 2145 * 1782 2146 * @returns VBox status code. … … 1784 2148 * @param pStreamEx Stream to control. 1785 2149 * @param enmStreamCmd Control command. 2150 * 2151 * @note Caller has entered the critical section. 1786 2152 */ 1787 2153 static int drvAudioStreamControlInternalBackend(PDRVAUDIO pThis, PDRVAUDIOSTREAM pStreamEx, PDMAUDIOSTREAMCMD enmStreamCmd) … … 1790 2156 AssertPtr(pStreamEx); 1791 2157 1792 #ifdef LOG_ENABLED1793 char szStreamSts[DRVAUDIO_STATUS_STR_MAX];1794 #endif1795 LogFlowFunc(("[%s] enmStreamCmd=%s, fStatus=%s\n", pStreamEx->Core.szName, PDMAudioStrmCmdGetName(enmStreamCmd),1796 dbgAudioStreamStatusToStr(szStreamSts, pStreamEx->Core.fStatus)));1797 1798 if (!pThis->pHostDrvAudio) /* If not lower driver is configured, bail out. */1799 return VINF_SUCCESS;1800 1801 1802 2158 /* 1803 2159 * Whether to propagate commands down to the backend. 1804 2160 * 1805 * This is needed for critical operations like recording audio if audio input is disabled on a per-driver level. 2161 * 1. If the stream direction is disabled on the driver level, we should 2162 * obviously not call the backend. Our stream status will reflect the 2163 * actual state so drvAudioEnable() can tell the backend if the user 2164 * re-enables the stream direction. 1806 2165 * 1807 * Note that not all commands will be covered by this, such as operations like stopping, draining and droppping, 1808 * which are considered uncritical and sometimes even are required for certain backends (like DirectSound on Windows). 1809 * 1810 * The actual stream state will be untouched to not make the state machine handling more complicated than 1811 * it already is. 1812 * 1813 * See @bugref{9882}. 1814 */ 1815 const bool fEnabled = ( pStreamEx->Core.enmDir == PDMAUDIODIR_IN 1816 && pThis->In.fEnabled) 1817 || ( pStreamEx->Core.enmDir == PDMAUDIODIR_OUT 1818 && pThis->Out.fEnabled); 1819 1820 LogRel2(("Audio: %s stream '%s' in backend (%s is %s)\n", PDMAudioStrmCmdGetName(enmStreamCmd), pStreamEx->Core.szName, 1821 PDMAudioDirGetName(pStreamEx->Core.enmDir), 1822 fEnabled ? "enabled" : "disabled")); 1823 int rc = VINF_SUCCESS; 1824 switch (enmStreamCmd) 1825 { 1826 case PDMAUDIOSTREAMCMD_ENABLE: 1827 { 1828 if (fEnabled) 1829 rc = pThis->pHostDrvAudio->pfnStreamControl(pThis->pHostDrvAudio, pStreamEx->pBackend, PDMAUDIOSTREAMCMD_ENABLE); 1830 break; 1831 } 1832 1833 case PDMAUDIOSTREAMCMD_DISABLE: 1834 { 1835 rc = pThis->pHostDrvAudio->pfnStreamControl(pThis->pHostDrvAudio, pStreamEx->pBackend, PDMAUDIOSTREAMCMD_DISABLE); 1836 break; 1837 } 1838 1839 case PDMAUDIOSTREAMCMD_PAUSE: 1840 { 1841 if (fEnabled) /* Needed, as resume below also is being checked for. */ 1842 rc = pThis->pHostDrvAudio->pfnStreamControl(pThis->pHostDrvAudio, pStreamEx->pBackend, PDMAUDIOSTREAMCMD_PAUSE); 1843 break; 1844 } 1845 1846 case PDMAUDIOSTREAMCMD_RESUME: 1847 { 1848 if (fEnabled) 1849 rc = pThis->pHostDrvAudio->pfnStreamControl(pThis->pHostDrvAudio, pStreamEx->pBackend, PDMAUDIOSTREAMCMD_RESUME); 1850 break; 1851 } 1852 1853 case PDMAUDIOSTREAMCMD_DRAIN: 1854 { 1855 rc = pThis->pHostDrvAudio->pfnStreamControl(pThis->pHostDrvAudio, pStreamEx->pBackend, PDMAUDIOSTREAMCMD_DRAIN); 1856 break; 1857 } 1858 1859 default: 1860 AssertMsgFailedReturn(("Command %RU32 not implemented\n", enmStreamCmd), VERR_INTERNAL_ERROR_2); 1861 } 1862 1863 if (RT_FAILURE(rc)) 1864 { 1865 if ( rc != VERR_NOT_IMPLEMENTED 1866 && rc != VERR_NOT_SUPPORTED 1867 && rc != VERR_AUDIO_STREAM_NOT_READY) 1868 { 1869 LogRel(("Audio: %s stream '%s' failed with %Rrc\n", PDMAudioStrmCmdGetName(enmStreamCmd), pStreamEx->Core.szName, rc)); 1870 } 1871 1872 LogFunc(("[%s] %s failed with %Rrc\n", pStreamEx->Core.szName, PDMAudioStrmCmdGetName(enmStreamCmd), rc)); 1873 } 1874 2166 * 2. If the backend hasn't finished initializing yet, don't try call 2167 * it to start/stop/pause/whatever the stream. (Better to do it here 2168 * than to replicate this in the relevant backends.) When the backend 2169 * finish initializing the stream, we'll update it about the stream state. 2170 */ 2171 int rc = VINF_SUCCESS; 2172 uint32_t const fBackendStatus = drvAudioStreamGetBackendStatus(pThis, pStreamEx); /* (checks pThis->pHostDrvAudio too) */ 2173 bool const fDirEnabled = pStreamEx->Core.enmDir == PDMAUDIODIR_IN ? pThis->In.fEnabled : pThis->Out.fEnabled; 2174 2175 char szStreamSts[DRVAUDIO_STATUS_STR_MAX], szBackendStreamSts[DRVAUDIO_STATUS_STR_MAX]; 2176 LogRel2(("Audio: %s stream '%s' backend (%s is %s; status: %s; backend-status: %s)\n", 2177 PDMAudioStrmCmdGetName(enmStreamCmd), pStreamEx->Core.szName, PDMAudioDirGetName(pStreamEx->Core.enmDir), 2178 fDirEnabled ? "enabled" : "disabled", dbgAudioStreamStatusToStr(szStreamSts, pStreamEx->fStatus), 2179 dbgAudioStreamStatusToStr(szBackendStreamSts, fBackendStatus) )); 2180 2181 if (fDirEnabled) 2182 { 2183 if ( (pStreamEx->fStatus & PDMAUDIOSTREAM_STS_BACKEND_READY) 2184 && (fBackendStatus & PDMAUDIOSTREAM_STS_INITIALIZED)) 2185 { 2186 /** @todo Backend will change to explicit methods here, so please don't simplify 2187 * the switch. */ 2188 switch (enmStreamCmd) 2189 { 2190 case PDMAUDIOSTREAMCMD_ENABLE: 2191 rc = pThis->pHostDrvAudio->pfnStreamControl(pThis->pHostDrvAudio, pStreamEx->pBackend, 2192 PDMAUDIOSTREAMCMD_ENABLE); 2193 break; 2194 2195 case PDMAUDIOSTREAMCMD_DISABLE: 2196 rc = pThis->pHostDrvAudio->pfnStreamControl(pThis->pHostDrvAudio, pStreamEx->pBackend, 2197 PDMAUDIOSTREAMCMD_DISABLE); 2198 break; 2199 2200 case PDMAUDIOSTREAMCMD_PAUSE: 2201 rc = pThis->pHostDrvAudio->pfnStreamControl(pThis->pHostDrvAudio, pStreamEx->pBackend, 2202 PDMAUDIOSTREAMCMD_PAUSE); 2203 break; 2204 2205 case PDMAUDIOSTREAMCMD_RESUME: 2206 rc = pThis->pHostDrvAudio->pfnStreamControl(pThis->pHostDrvAudio, pStreamEx->pBackend, 2207 PDMAUDIOSTREAMCMD_RESUME); 2208 break; 2209 2210 case PDMAUDIOSTREAMCMD_DRAIN: 2211 rc = pThis->pHostDrvAudio->pfnStreamControl(pThis->pHostDrvAudio, pStreamEx->pBackend, 2212 PDMAUDIOSTREAMCMD_DRAIN); 2213 break; 2214 2215 default: 2216 AssertMsgFailedReturn(("Command %RU32 not implemented\n", enmStreamCmd), VERR_INTERNAL_ERROR_2); 2217 } 2218 if (RT_SUCCESS(rc)) 2219 Log2Func(("[%s] %s succeeded (%Rrc)\n", pStreamEx->Core.szName, PDMAudioStrmCmdGetName(enmStreamCmd), rc)); 2220 else 2221 { 2222 LogFunc(("[%s] %s failed with %Rrc\n", pStreamEx->Core.szName, PDMAudioStrmCmdGetName(enmStreamCmd), rc)); 2223 if ( rc != VERR_NOT_IMPLEMENTED 2224 && rc != VERR_NOT_SUPPORTED 2225 && rc != VERR_AUDIO_STREAM_NOT_READY) 2226 LogRel(("Audio: %s stream '%s' failed with %Rrc\n", PDMAudioStrmCmdGetName(enmStreamCmd), pStreamEx->Core.szName, rc)); 2227 } 2228 } 2229 } 1875 2230 return rc; 1876 2231 } … … 1888 2243 LogFunc(("[%s]\n", pStreamEx->Core.szName)); 1889 2244 1890 pStreamEx-> Core.fStatus = PDMAUDIOSTREAM_STS_INITIALIZED;2245 pStreamEx->fStatus &= PDMAUDIOSTREAM_STS_INITIALIZED | PDMAUDIOSTREAM_STS_BACKEND_READY; 1891 2246 pStreamEx->Core.fWarningsShown = PDMAUDIOSTREAM_WARN_FLAGS_NONE; 1892 2247 … … 1927 2282 { 1928 2283 if ( pStreamEx->uMagic == DRVAUDIOSTREAM_MAGIC 1929 && pStreamEx-> Core.cRefs >= 1)1930 { 1931 if (pStreamEx-> Core.fStatus & PDMAUDIOSTREAM_STS_PENDING_DISABLE)2284 && pStreamEx->cRefs >= 1) 2285 { 2286 if (pStreamEx->fStatus & PDMAUDIOSTREAM_STS_PENDING_DISABLE) 1932 2287 { 1933 2288 drvAudioStreamIterateInternal(pThis, pStreamEx); 1934 2289 1935 if (pStreamEx-> Core.fStatus & PDMAUDIOSTREAM_STS_PENDING_DISABLE)2290 if (pStreamEx->fStatus & PDMAUDIOSTREAM_STS_PENDING_DISABLE) 1936 2291 cMilliesToNext = 10; 1937 2292 } … … 1971 2326 #endif 1972 2327 LogFunc(("[%s] enmStreamCmd=%s fStatus=%s\n", pStreamEx->Core.szName, PDMAudioStrmCmdGetName(enmStreamCmd), 1973 dbgAudioStreamStatusToStr(szStreamSts, pStreamEx-> Core.fStatus)));2328 dbgAudioStreamStatusToStr(szStreamSts, pStreamEx->fStatus))); 1974 2329 1975 2330 int rc = VINF_SUCCESS; … … 1978 2333 { 1979 2334 case PDMAUDIOSTREAMCMD_ENABLE: 1980 if (!(pStreamEx-> Core.fStatus & PDMAUDIOSTREAM_STS_ENABLED))2335 if (!(pStreamEx->fStatus & PDMAUDIOSTREAM_STS_ENABLED)) 1981 2336 { 1982 2337 /* Is a pending disable outstanding? Then disable first. */ 1983 if (pStreamEx-> Core.fStatus & PDMAUDIOSTREAM_STS_PENDING_DISABLE)2338 if (pStreamEx->fStatus & PDMAUDIOSTREAM_STS_PENDING_DISABLE) 1984 2339 rc = drvAudioStreamControlInternalBackend(pThis, pStreamEx, PDMAUDIOSTREAMCMD_DISABLE); 1985 2340 if (RT_SUCCESS(rc)) … … 1993 2348 pStreamEx->Out.enmPlayState = pStreamEx->Out.cbPreBufThreshold > 0 1994 2349 ? DRVAUDIOPLAYSTATE_PREBUF 1995 : pStreamEx->fLastBackendStatus & PDMAUDIOSTREAM_STS_INITIALIZED 2350 : (pStreamEx->fStatus & PDMAUDIOSTREAM_STS_BACKEND_READY) 2351 && (pStreamEx->fLastBackendStatus & PDMAUDIOSTREAM_STS_INITIALIZED) 1996 2352 ? DRVAUDIOPLAYSTATE_PLAY 1997 2353 : DRVAUDIOPLAYSTATE_NOPLAY; … … 2005 2361 if (RT_SUCCESS(rc)) 2006 2362 { 2007 pStreamEx-> Core.fStatus |= PDMAUDIOSTREAM_STS_ENABLED;2008 PDMAUDIOSTREAM_STS_ASSERT_VALID(pStreamEx-> Core.fStatus);2363 pStreamEx->fStatus |= PDMAUDIOSTREAM_STS_ENABLED; 2364 PDMAUDIOSTREAM_STS_ASSERT_VALID(pStreamEx->fStatus); 2009 2365 } 2010 2366 } … … 2013 2369 2014 2370 case PDMAUDIOSTREAMCMD_DISABLE: 2015 if (pStreamEx-> Core.fStatus & PDMAUDIOSTREAM_STS_ENABLED)2371 if (pStreamEx->fStatus & PDMAUDIOSTREAM_STS_ENABLED) 2016 2372 { 2017 2373 /* … … 2023 2379 { 2024 2380 LogFunc(("[%s] Pending disable/pause\n", pStreamEx->Core.szName)); 2025 pStreamEx-> Core.fStatus |= PDMAUDIOSTREAM_STS_PENDING_DISABLE;2026 PDMAUDIOSTREAM_STS_ASSERT_VALID(pStreamEx-> Core.fStatus);2381 pStreamEx->fStatus |= PDMAUDIOSTREAM_STS_PENDING_DISABLE; 2382 PDMAUDIOSTREAM_STS_ASSERT_VALID(pStreamEx->fStatus); 2027 2383 2028 2384 /* Schedule a follow up timer to the pending-disable state. We cannot rely … … 2040 2396 2041 2397 /* Can we close the host stream as well (not in pending disable mode)? */ 2042 if (!(pStreamEx-> Core.fStatus & PDMAUDIOSTREAM_STS_PENDING_DISABLE))2398 if (!(pStreamEx->fStatus & PDMAUDIOSTREAM_STS_PENDING_DISABLE)) 2043 2399 { 2044 2400 rc = drvAudioStreamControlInternalBackend(pThis, pStreamEx, PDMAUDIOSTREAMCMD_DISABLE); … … 2050 2406 2051 2407 case PDMAUDIOSTREAMCMD_PAUSE: 2052 if ( (pStreamEx->Core.fStatus & (PDMAUDIOSTREAM_STS_ENABLED | PDMAUDIOSTREAM_STS_PAUSED)) 2053 == PDMAUDIOSTREAM_STS_ENABLED) 2408 if ((pStreamEx->fStatus & (PDMAUDIOSTREAM_STS_ENABLED | PDMAUDIOSTREAM_STS_PAUSED)) == PDMAUDIOSTREAM_STS_ENABLED) 2054 2409 { 2055 2410 rc = drvAudioStreamControlInternalBackend(pThis, pStreamEx, PDMAUDIOSTREAMCMD_PAUSE); 2056 2411 if (RT_SUCCESS(rc)) 2057 2412 { 2058 pStreamEx-> Core.fStatus |= PDMAUDIOSTREAM_STS_PAUSED;2059 PDMAUDIOSTREAM_STS_ASSERT_VALID(pStreamEx-> Core.fStatus);2413 pStreamEx->fStatus |= PDMAUDIOSTREAM_STS_PAUSED; 2414 PDMAUDIOSTREAM_STS_ASSERT_VALID(pStreamEx->fStatus); 2060 2415 } 2061 2416 } … … 2063 2418 2064 2419 case PDMAUDIOSTREAMCMD_RESUME: 2065 if (pStreamEx-> Core.fStatus & PDMAUDIOSTREAM_STS_PAUSED)2420 if (pStreamEx->fStatus & PDMAUDIOSTREAM_STS_PAUSED) 2066 2421 { 2067 Assert(pStreamEx-> Core.fStatus & PDMAUDIOSTREAM_STS_ENABLED);2422 Assert(pStreamEx->fStatus & PDMAUDIOSTREAM_STS_ENABLED); 2068 2423 rc = drvAudioStreamControlInternalBackend(pThis, pStreamEx, PDMAUDIOSTREAMCMD_RESUME); 2069 2424 if (RT_SUCCESS(rc)) 2070 2425 { 2071 pStreamEx-> Core.fStatus &= ~PDMAUDIOSTREAM_STS_PAUSED;2072 PDMAUDIOSTREAM_STS_ASSERT_VALID(pStreamEx-> Core.fStatus);2426 pStreamEx->fStatus &= ~PDMAUDIOSTREAM_STS_PAUSED; 2427 PDMAUDIOSTREAM_STS_ASSERT_VALID(pStreamEx->fStatus); 2073 2428 } 2074 2429 } … … 2178 2533 * Update the pre-buffering size and position. 2179 2534 */ 2180 pStreamEx->Out.cbPreBuffered = cbCur;2535 pStreamEx->Out.cbPreBuffered = RT_MIN(cbCur, cbMax); 2181 2536 pStreamEx->Out.offPreBuf = offRead; 2182 2537 return VINF_SUCCESS; … … 2184 2539 2185 2540 2186 #if 0 2187 /** 2188 * Worker for drvAudioStreamPlay() and drvAudioStreamIterateInternal(). 2189 * 2190 * The buffer is NULL and has a zero length when called from the interate 2191 * function. This only occures when there is pre-buffered audio data that need 2192 * to be pushed to the backend due to a pending disabling of the stream. 2193 * 2194 * Caller owns the lock. 2195 */ 2196 static int drvAudioStreamPlayLocked(PDRVAUDIO pThis, PDRVAUDIOSTREAM pStreamEx, uint32_t fBackStatus, 2197 const uint8_t *pbBuf, uint32_t cbBuf, uint32_t *pcbWritten) 2198 { 2199 Log3Func(("%s: @%#RX64: cbBuf=%#x fBackStatus=%#x\n", pStreamEx->Core.szName, pStreamEx->offInternal, cbBuf, fBackStatus)); 2200 RT_NOREF(fBackStatus); 2201 2202 /* 2203 * Are we pre-buffering? 2204 * 2205 * Note! We do not restart pre-buffering in this version, as we'd 2206 * need some kind of cooperation with the backend buffer 2207 * managment to correctly detect an underrun. 2208 */ 2209 bool fJustStarted = false; 2210 uint32_t cbWritten = 0; 2211 int rc; 2212 if ( pStreamEx->fThresholdReached 2213 && pStreamEx->Out.cbPreBuffered == 0) 2214 { 2215 /* not-prebuffering, likely after a while at least */ 2216 rc = VINF_SUCCESS; 2217 } 2218 else 2219 { 2220 /* 2221 * Copy as much as we can to the pre-buffer. 2222 */ 2223 uint32_t cbFree = pStreamEx->Out.cbPreBufAlloc - pStreamEx->Out.cbPreBuffered; 2224 AssertReturn((int32_t)cbFree >= 0, VERR_INTERNAL_ERROR_2); 2225 if (cbFree > 0 && cbBuf > 0) 2226 { 2227 cbWritten = RT_MIN(cbFree, cbBuf); 2228 cbWritten = PDMAudioPropsFloorBytesToFrame(&pStreamEx->Core.Props, cbWritten); 2229 if (pStreamEx->Out.offPreBuf == 0) 2230 memcpy(&pStreamEx->Out.pbPreBuf[pStreamEx->Out.cbPreBuffered], pbBuf, cbWritten); 2231 else 2232 { 2233 2234 } 2235 2236 pStreamEx->Out.cbPreBuffered += cbWritten; 2237 cbBuf -= cbWritten; 2238 pbBuf += cbWritten; 2239 pStreamEx->offInternal += cbWritten; 2240 } 2241 2242 /* 2243 * Get the special case of buggy backend drivers out of the way. 2244 * We get here if we couldn't write out all the pre-buffered data when 2245 * we hit the threshold. 2246 */ 2247 if (pStreamEx->fThresholdReached) 2248 LogRel2(("Audio: @%#RX64: Stream '%s' pre-buffering commit problem: cbBuf=%#x cbPreBuffered=%#x\n", 2249 pStreamEx->offInternal, pStreamEx->Core.szName, cbBuf, pStreamEx->Out.cbPreBuffered)); 2250 /* 2251 * Did we reach the backend's playback (pre-buffering) threshold? 2252 * Can be 0 if no pre-buffering desired. 2253 */ 2254 else if (pStreamEx->Out.cbPreBuffered + cbBuf >= pStreamEx->Out.cbPreBufThreshold) 2255 { 2256 LogRel2(("Audio: @%#RX64: Stream '%s' buffering complete! (%#x + %#x bytes)\n", 2257 pStreamEx->offInternal, pStreamEx->Core.szName, pStreamEx->Out.cbPreBuffered, cbBuf)); 2258 pStreamEx->fThresholdReached = fJustStarted = true; 2259 } 2260 /* 2261 * Some audio files are shorter than the pre-buffering level (e.g. the 2262 * "click" Explorer sounds on some Windows guests), so make sure that we 2263 * also play those by checking if the stream already is pending disable 2264 * mode, even if we didn't hit the pre-buffering watermark yet. 2265 * 2266 * Try play "Windows Navigation Start.wav" on Windows 7 (2824 samples). 2267 */ 2268 else if ( (pStreamEx->Core.fStatus & PDMAUDIOSTREAM_STS_PENDING_DISABLE) 2269 && pStreamEx->Out.cbPreBuffered > 0) 2270 { 2271 LogRel2(("Audio: @%#RX64: Stream '%s' buffering complete - short sound! (%#x + %#x bytes)\n", 2272 pStreamEx->offInternal, pStreamEx->Core.szName, pStreamEx->Out.cbPreBuffered, cbBuf)); 2273 pStreamEx->fThresholdReached = fJustStarted = true; 2274 } 2275 /* 2276 * Not yet, so still buffering audio data. 2277 */ 2278 else 2279 { 2280 LogRel2(("Audio: @%#RX64: Stream '%s' is buffering (%RU8%% complete)...\n", pStreamEx->offInternal, 2281 pStreamEx->Core.szName, (100 * pStreamEx->Out.cbPreBuffered) / pStreamEx->Out.cbPreBufThreshold)); 2282 Assert(cbBuf == 0); 2283 *pcbWritten = cbWritten; 2284 return VINF_SUCCESS; 2285 } 2286 2287 /* 2288 * Write the pre-buffered chunk. 2289 */ 2290 uint32_t off = 0; 2291 uint32_t cbPreBufWritten; 2292 do 2293 { 2294 cbPreBufWritten = 0; 2295 rc = pThis->pHostDrvAudio->pfnStreamPlay(pThis->pHostDrvAudio, pStreamEx->pBackend, &pStreamEx->Out.pbPreBuf[off], 2296 pStreamEx->Out.cbPreBuffered - off, &cbPreBufWritten); 2297 AssertRCBreak(rc); 2298 off += cbPreBufWritten; 2299 } while (off < pStreamEx->Out.cbPreBuffered && cbPreBufWritten != 0); 2300 2301 if (off >= pStreamEx->Out.cbPreBuffered) 2302 { 2303 Assert(off == pStreamEx->Out.cbPreBuffered); 2304 LogFunc(("@%#RX64: Wrote all %#x bytes of pre-buffered audio data.\n", pStreamEx->offInternal, off)); 2305 pStreamEx->Out.cbPreBuffered = 0; 2306 } 2307 else 2308 { 2309 LogRel2(("Audio: @%#RX64: Stream '%s' pre-buffering commit problem: wrote %#x out of %#x + %#x%s - rc=%Rrc *pcbWritten=%#x\n", 2310 pStreamEx->offInternal, pStreamEx->Core.szName, off, pStreamEx->Out.cbPreBuffered, cbBuf, 2311 fJustStarted ? " (just started)" : "", rc, cbWritten)); 2312 AssertMsg(!fJustStarted || RT_FAILURE(rc), 2313 ("Buggy host driver buffer reporting: off=%#x cbPreBuffered=%#x\n", off, pStreamEx->Out.cbPreBuffered)); 2314 if (off > 0) 2315 { 2316 memmove(pStreamEx->Out.pbPreBuf, &pStreamEx->Out.pbPreBuf[off], pStreamEx->Out.cbPreBuffered - off); 2317 pStreamEx->Out.cbPreBuffered -= off; 2318 } 2319 pStreamEx->nsLastPlayedCaptured = RTTimeNanoTS(); 2320 *pcbWritten = cbWritten; 2321 return cbWritten ? VINF_SUCCESS : rc; 2322 } 2323 2324 if (RT_FAILURE(rc)) 2325 { 2326 *pcbWritten = cbWritten; 2327 return rc; 2328 } 2329 } 2330 2331 /* 2332 * Do the writing. 2333 */ 2334 uint32_t cbWritable = pThis->pHostDrvAudio->pfnStreamGetWritable(pThis->pHostDrvAudio, pStreamEx->pBackend); 2335 pStreamEx->Out.Stats.cbBackendWritableBefore = cbWritable; 2336 2337 uint8_t const cbFrame = PDMAudioPropsFrameSize(&pStreamEx->Core.Props); 2338 while (cbBuf >= cbFrame && cbWritable >= cbFrame) 2339 { 2340 uint32_t const cbToWrite = PDMAudioPropsFloorBytesToFrame(&pStreamEx->Core.Props, RT_MIN(cbBuf, cbWritable)); 2341 uint32_t cbWrittenNow = 0; 2342 rc = pThis->pHostDrvAudio->pfnStreamPlay(pThis->pHostDrvAudio, pStreamEx->pBackend, pbBuf, cbToWrite, &cbWrittenNow); 2343 if (RT_SUCCESS(rc)) 2344 { 2345 if (cbWrittenNow != cbToWrite) 2346 Log3Func(("%s: @%#RX64: Wrote less bytes than requested: %#x, requested %#x\n", 2347 pStreamEx->Core.szName, pStreamEx->offInternal, cbWrittenNow, cbToWrite)); 2348 #ifdef DEBUG_bird 2349 Assert(cbWrittenNow == cbToWrite); 2350 #endif 2351 AssertStmt(cbWrittenNow <= cbToWrite, cbWrittenNow = cbToWrite); 2352 cbWritten += cbWrittenNow; 2353 cbBuf -= cbWrittenNow; 2354 pbBuf += cbWrittenNow; 2355 pStreamEx->offInternal += cbWrittenNow; 2356 } 2357 else 2358 { 2359 *pcbWritten = cbWritten; 2360 LogFunc(("%s: @%#RX64: pfnStreamPlay failed writing %#x bytes (%#x previous written, %#x writable): %Rrc\n", 2361 pStreamEx->Core.szName, pStreamEx->offInternal, cbToWrite, cbWritten, cbWritable, rc)); 2362 return cbWritten ? VINF_SUCCESS : rc; 2363 } 2364 cbWritable = pThis->pHostDrvAudio->pfnStreamGetWritable(pThis->pHostDrvAudio, pStreamEx->pBackend); 2365 } 2366 2367 *pcbWritten = cbWritten; 2368 pStreamEx->Out.Stats.cbBackendWritableAfter = cbWritable; 2369 if (cbWritten) 2370 pStreamEx->nsLastPlayedCaptured = RTTimeNanoTS(); 2371 2372 Log3Func(("%s: @%#RX64: Wrote %#x bytes (%#x bytes left)\n", pStreamEx->Core.szName, pStreamEx->offInternal, cbWritten, cbBuf)); 2373 return rc; 2374 } 2375 #endif 2376 2377 2378 /** 2379 * Worker for drvAudioStreamPlay() and drvAudioStreamIterateInternal(). 2541 /** 2542 * Worker for drvAudioStreamPlay() and drvAudioStreamPreBufComitting(). 2380 2543 * 2381 2544 * Caller owns the lock. … … 2432 2595 2433 2596 2597 /** 2598 * Worker for drvAudioStreamPlay() and drvAudioStreamPreBufComitting(). 2599 */ 2434 2600 static int drvAudioStreamPlayToPreBuffer(PDRVAUDIOSTREAM pStreamEx, const void *pvBuf, uint32_t cbBuf, uint32_t cbMax, 2435 2601 uint32_t *pcbWritten) … … 2563 2729 AssertPtrReturn(pThis, VERR_INVALID_POINTER); 2564 2730 2565 if (!pThis->pHostDrvAudio)2566 return VINF_SUCCESS;2567 2568 2731 #ifdef LOG_ENABLED 2569 2732 char szStreamSts[DRVAUDIO_STATUS_STR_MAX]; 2570 2733 #endif 2571 Log3Func(("[%s] fStatus=%s\n", pStreamEx->Core.szName, dbgAudioStreamStatusToStr(szStreamSts, pStreamEx-> Core.fStatus)));2734 Log3Func(("[%s] fStatus=%s\n", pStreamEx->Core.szName, dbgAudioStreamStatusToStr(szStreamSts, pStreamEx->fStatus))); 2572 2735 2573 2736 /* Not enabled or paused? Skip iteration. */ 2574 if ( !(pStreamEx->Core.fStatus & PDMAUDIOSTREAM_STS_ENABLED) 2575 || (pStreamEx->Core.fStatus & PDMAUDIOSTREAM_STS_PAUSED)) 2576 { 2737 if ((pStreamEx->fStatus & (PDMAUDIOSTREAM_STS_ENABLED | PDMAUDIOSTREAM_STS_PAUSED)) != PDMAUDIOSTREAM_STS_ENABLED) 2577 2738 return VINF_SUCCESS; 2578 }2579 2739 2580 2740 /* … … 2582 2742 */ 2583 2743 int rc = VINF_SUCCESS; 2584 if (!(pStreamEx-> Core.fStatus & PDMAUDIOSTREAM_STS_PENDING_DISABLE))2744 if (!(pStreamEx->fStatus & PDMAUDIOSTREAM_STS_PENDING_DISABLE)) 2585 2745 { /* likely until we get to the end of the stream at least. */ } 2586 2746 else … … 2617 2777 if (pStreamEx->Out.cbPreBuffered > 0) 2618 2778 { 2619 uint32_t cbIgnored = 0; 2620 drvAudioStreamPreBufComitting(pThis, pStreamEx, NULL, 0, &cbIgnored); 2621 cFramesLive = PDMAudioPropsBytesToFrames(&pStreamEx->Core.Props, pStreamEx->Out.cbPreBuffered); 2779 /* Must check the backend state here first and only try commit the 2780 pre-buffered samples if the backend is in working order. */ 2781 uint32_t const fBackendStatus = drvAudioStreamGetBackendStatus(pThis, pStreamEx); /* (checks pThis->pHostDrvAudio too) */ 2782 if ( (pStreamEx->fStatus & PDMAUDIOSTREAM_STS_BACKEND_READY) 2783 && (fBackendStatus & PDMAUDIOSTREAM_STS_INITIALIZED)) 2784 { 2785 uint32_t cbIgnored = 0; 2786 drvAudioStreamPreBufComitting(pThis, pStreamEx, NULL, 0, &cbIgnored); 2787 cFramesLive = PDMAudioPropsBytesToFrames(&pStreamEx->Core.Props, pStreamEx->Out.cbPreBuffered); 2788 } 2789 else 2790 Log3Func(("[%s] Skipping committing pre-buffered samples, backend not initialized (%#x)!\n", 2791 pStreamEx->Core.szName, fBackendStatus)); 2622 2792 } 2623 2793 break; … … 2633 2803 if (rc == VERR_NOT_SUPPORTED) /* Not all backends support draining yet. */ 2634 2804 rc = VINF_SUCCESS; 2805 /** @todo r=bird: We could probably just skip this next check, as if drainig 2806 * failes, we should definitely try disable the stream. Maybe the 2807 * host audio device was unplugged and we're leaving this stream in a 2808 * bogus state. */ 2635 2809 if (RT_SUCCESS(rc)) 2636 2810 { 2637 2811 /* 2638 * Before we disable the stream, check if the backend has 2639 * finished playing the buffered data. 2812 * Before we disable the stream, check if the backend has finished playing the buffered data. 2640 2813 */ 2641 2814 uint32_t cbPending; 2642 if (!pThis->pHostDrvAudio ->pfnStreamGetPending) /* Optional. */2815 if (!pThis->pHostDrvAudio || !pThis->pHostDrvAudio->pfnStreamGetPending) /* Optional. */ 2643 2816 cbPending = 0; 2644 2817 else … … 2656 2829 if (RT_SUCCESS(rc)) 2657 2830 { 2658 pStreamEx-> Core.fStatus &= ~(PDMAUDIOSTREAM_STS_ENABLED | PDMAUDIOSTREAM_STS_PENDING_DISABLE);2659 PDMAUDIOSTREAM_STS_ASSERT_VALID(pStreamEx-> Core.fStatus);2831 pStreamEx->fStatus &= ~(PDMAUDIOSTREAM_STS_ENABLED | PDMAUDIOSTREAM_STS_PENDING_DISABLE); 2832 PDMAUDIOSTREAM_STS_ASSERT_VALID(pStreamEx->fStatus); 2660 2833 drvAudioStreamDropInternal(pStreamEx); /* Not a DROP command, just a stream reset. */ 2661 2834 } 2835 /** @todo r=bird: This log entry sounds a rather fishy to be honest... Any 2836 * backend which would do that, or genuinely need this? */ 2662 2837 else 2663 2838 LogFunc(("[%s] Backend vetoed against closing pending input stream, rc=%Rrc\n", pStreamEx->Core.szName, rc)); … … 2665 2840 } 2666 2841 } 2667 2668 2842 } 2669 2843 … … 2727 2901 2728 2902 if ( pThis->pHostDrvAudio 2729 && ( PDMAudioStrmStatusCanRead(pStreamEx-> Core.fStatus)2903 && ( PDMAudioStrmStatusCanRead(pStreamEx->fStatus) 2730 2904 || fDisabled) 2731 2905 ) 2732 2906 { 2907 uint32_t const fBackendStatus = drvAudioStreamGetBackendStatus(pThis, pStreamEx); 2908 2733 2909 if (pStreamEx->fNoMixBufs) 2734 cbReadable = pThis->pHostDrvAudio 2735 ? pThis->pHostDrvAudio->pfnStreamGetReadable(pThis->pHostDrvAudio, pStreamEx->pBackend) : 0; 2910 cbReadable = pThis->pHostDrvAudio 2911 && (pStreamEx->fStatus & PDMAUDIOSTREAM_STS_BACKEND_READY) 2912 && (fBackendStatus & PDMAUDIOSTREAM_STS_INITIALIZED) 2913 && !fDisabled 2914 ? pThis->pHostDrvAudio->pfnStreamGetReadable(pThis->pHostDrvAudio, pStreamEx->pBackend) 2915 : 0; 2736 2916 else 2737 2917 { … … 2739 2919 cbReadable = AUDIOMIXBUF_F2B(&pStreamEx->Guest.MixBuf, cfReadable); 2740 2920 } 2741 2742 2921 if (!cbReadable) 2743 2922 { … … 2750 2929 * Reading the actual data from a stream then will return silence then. 2751 2930 */ 2752 uint32_t fStatus = drvAudioStreamGetBackendStatus(pThis, pStreamEx); 2753 if ( !PDMAudioStrmStatusBackendCanRead(fStatus) 2931 if ( !PDMAudioStrmStatusBackendCanRead(fBackendStatus) 2754 2932 || fDisabled) 2755 2933 { … … 2762 2940 else 2763 2941 LogRel(("Audio: Warning: Input for stream '%s' of driver '%s' not ready (current input status is %#x), returning silence\n", 2764 pStreamEx->Core.szName, pThis->szName, f Status));2942 pStreamEx->Core.szName, pThis->szName, fBackendStatus)); 2765 2943 2766 2944 pStreamEx->Core.fWarningsShown |= PDMAUDIOSTREAM_WARN_FLAGS_DISABLED; … … 2803 2981 */ 2804 2982 uint32_t cbWritable = 0; 2805 if ( PDMAudioStrmStatusCanWrite(pStreamEx-> Core.fStatus)2983 if ( PDMAudioStrmStatusCanWrite(pStreamEx->fStatus) 2806 2984 && pThis->pHostDrvAudio != NULL) 2807 2985 { 2808 Assert(pThis->pHostDrvAudio);2809 2986 switch (pStreamEx->Out.enmPlayState) 2810 2987 { … … 2814 2991 case DRVAUDIOPLAYSTATE_PLAY: 2815 2992 case DRVAUDIOPLAYSTATE_PLAY_PREBUF: 2993 Assert(pStreamEx->fStatus & PDMAUDIOSTREAM_STS_BACKEND_READY); 2994 Assert(drvAudioStreamGetBackendStatus(pThis, pStreamEx) & PDMAUDIOSTREAM_STS_INITIALIZED); 2816 2995 cbWritable = pThis->pHostDrvAudio->pfnStreamGetWritable(pThis->pHostDrvAudio, pStreamEx->pBackend); 2817 2996 break; … … 2850 3029 as long as there is space for it, as we need the pfnStreamWrite call 2851 3030 to move the data. */ 3031 Assert(pStreamEx->fStatus & PDMAUDIOSTREAM_STS_BACKEND_READY); 3032 Assert(drvAudioStreamGetBackendStatus(pThis, pStreamEx) & PDMAUDIOSTREAM_STS_INITIALIZED); 2852 3033 uint32_t const cbMin = PDMAudioPropsFramesToBytes(&pStreamEx->Core.Props, 8); 2853 3034 cbWritable = pThis->pHostDrvAudio->pfnStreamGetWritable(pThis->pHostDrvAudio, pStreamEx->pBackend); … … 2899 3080 AssertRCReturn(rc, PDMAUDIOSTREAM_STS_NONE); 2900 3081 2901 uint32_t fStrmStatus = pStreamEx-> Core.fStatus;3082 uint32_t fStrmStatus = pStreamEx->fStatus; 2902 3083 2903 3084 RTCritSectLeave(&pThis->CritSect); … … 2932 3113 2933 3114 3115 /** 3116 * Processes backend status change. 3117 * 3118 * @todo bird: I'm more and more of the opinion that the backend should 3119 * explicitly notify us about these changes, rather that we polling them 3120 * via PDMIHOSTAUDIO::pfnStreamGetStatus... 3121 */ 2934 3122 static void drvAudioStreamPlayProcessBackendStateChange(PDRVAUDIOSTREAM pStreamEx, uint32_t fNewState, uint32_t fOldState) 2935 3123 { … … 2943 3131 if (fOldState & PDMAUDIOSTREAM_STS_INITIALIZED) 2944 3132 { 3133 /* Pulse audio clear INITIALIZED. */ 2945 3134 switch (enmPlayState) 2946 3135 { … … 2970 3159 else 2971 3160 { 2972 switch (enmPlayState)3161 if (pStreamEx->fStatus & PDMAUDIOSTREAM_STS_BACKEND_READY) 2973 3162 { 2974 case DRVAUDIOPLAYSTATE_PREBUF: 2975 case DRVAUDIOPLAYSTATE_PREBUF_SWITCHING: 2976 break; 2977 case DRVAUDIOPLAYSTATE_PREBUF_OVERDUE: 2978 pStreamEx->Out.enmPlayState = DRVAUDIOPLAYSTATE_PREBUF_COMMITTING; 2979 break; 2980 case DRVAUDIOPLAYSTATE_NOPLAY: 2981 pStreamEx->Out.enmPlayState = DRVAUDIOPLAYSTATE_PREBUF; 2982 break; 2983 case DRVAUDIOPLAYSTATE_PLAY: 2984 case DRVAUDIOPLAYSTATE_PLAY_PREBUF: 2985 case DRVAUDIOPLAYSTATE_PREBUF_COMMITTING: 2986 AssertFailedBreak(); 2987 /* no default */ 2988 case DRVAUDIOPLAYSTATE_END: 2989 case DRVAUDIOPLAYSTATE_INVALID: 2990 break; 3163 /** @todo We need to resync the stream status somewhere... */ 3164 switch (enmPlayState) 3165 { 3166 case DRVAUDIOPLAYSTATE_PREBUF: 3167 case DRVAUDIOPLAYSTATE_PREBUF_SWITCHING: 3168 break; 3169 case DRVAUDIOPLAYSTATE_PREBUF_OVERDUE: 3170 pStreamEx->Out.enmPlayState = DRVAUDIOPLAYSTATE_PREBUF_COMMITTING; 3171 break; 3172 case DRVAUDIOPLAYSTATE_NOPLAY: 3173 pStreamEx->Out.enmPlayState = DRVAUDIOPLAYSTATE_PREBUF; 3174 break; 3175 case DRVAUDIOPLAYSTATE_PLAY: 3176 case DRVAUDIOPLAYSTATE_PLAY_PREBUF: 3177 case DRVAUDIOPLAYSTATE_PREBUF_COMMITTING: 3178 AssertFailedBreak(); 3179 /* no default */ 3180 case DRVAUDIOPLAYSTATE_END: 3181 case DRVAUDIOPLAYSTATE_INVALID: 3182 break; 3183 } 3184 LogFunc(("PDMAUDIOSTREAM_STS_INITIALIZED was set: %s -> %s\n", 3185 drvAudioPlayStateName(enmPlayState), drvAudioPlayStateName(pStreamEx->Out.enmPlayState) )); 2991 3186 } 2992 LogFunc(("PDMAUDIOSTREAM_STS_INITIALIZED was set: %s -> %s\n", 2993 drvAudioPlayStateName(enmPlayState), drvAudioPlayStateName(pStreamEx->Out.enmPlayState) )); 3187 else 3188 LogFunc(("PDMAUDIOSTREAM_STS_INITIALIZED was set (enmPlayState=%s), but PDMAUDIOSTREAM_STS_BACKEND_READY is not.\n", 3189 drvAudioPlayStateName(enmPlayState) )); 2994 3190 } 2995 3191 } … … 2999 3195 * 3000 3196 * Note! We don't care if it's cleared as the backend will call 3001 * PDMI AUDIONOTIFYFROMHOST::pfnStreamNotifyDeviceChanged when that takes place.3197 * PDMIHOSTAUDIOPORT::pfnStreamNotifyDeviceChanged when that takes place. 3002 3198 */ 3003 3199 if ( !(fOldState & PDMAUDIOSTREAM_STS_PREPARING_SWITCH) … … 3073 3269 * whether to just drop the input into the bit bucket. 3074 3270 */ 3075 if (PDMAudioStrmStatusIsReady(pStreamEx-> Core.fStatus))3271 if (PDMAudioStrmStatusIsReady(pStreamEx->fStatus)) 3076 3272 { 3077 3273 if ( pThis->Out.fEnabled /* (see @bugref{9882}) */ … … 3097 3293 */ 3098 3294 uint32_t const fBackendStatus = drvAudioStreamGetBackendStatus(pThis, pStreamEx); 3099 Assert( (fBackendStatus & (PDMAUDIOSTREAM_STS_ENABLED | PDMAUDIOSTREAM_STS_PAUSED)) 3100 == (pStreamEx->Core.fStatus & (PDMAUDIOSTREAM_STS_ENABLED | PDMAUDIOSTREAM_STS_PAUSED)) ); 3295 Assert( (fBackendStatus & (PDMAUDIOSTREAM_STS_ENABLED | PDMAUDIOSTREAM_STS_PAUSED)) 3296 == (pStreamEx->fStatus & (PDMAUDIOSTREAM_STS_ENABLED | PDMAUDIOSTREAM_STS_PAUSED)) 3297 || !(pStreamEx->fStatus & PDMAUDIOSTREAM_STS_BACKEND_READY) 3298 || !(fBackendStatus & PDMAUDIOSTREAM_STS_INITIALIZED) ); 3101 3299 3102 3300 if (!( (pStreamEx->fLastBackendStatus ^ fBackendStatus) … … 3115 3313 { 3116 3314 case DRVAUDIOPLAYSTATE_PLAY: 3315 Assert(pStreamEx->fStatus & PDMAUDIOSTREAM_STS_BACKEND_READY); 3316 Assert(fBackendStatus & PDMAUDIOSTREAM_STS_INITIALIZED); 3117 3317 rc = drvAudioStreamPlayLocked(pThis, pStreamEx, (uint8_t const *)pvBuf, cbBuf, pcbWritten); 3118 3318 break; 3119 3319 3120 3320 case DRVAUDIOPLAYSTATE_PLAY_PREBUF: 3321 Assert(pStreamEx->fStatus & PDMAUDIOSTREAM_STS_BACKEND_READY); 3322 Assert(fBackendStatus & PDMAUDIOSTREAM_STS_INITIALIZED); 3121 3323 rc = drvAudioStreamPlayLocked(pThis, pStreamEx, (uint8_t const *)pvBuf, cbBuf, pcbWritten); 3122 3324 drvAudioStreamPreBuffer(pStreamEx, (uint8_t const *)pvBuf, *pcbWritten, pStreamEx->Out.cbPreBufThreshold); … … 3144 3346 3145 3347 case DRVAUDIOPLAYSTATE_PREBUF_OVERDUE: 3348 Assert(!(pStreamEx->fStatus & PDMAUDIOSTREAM_STS_BACKEND_READY)); 3146 3349 Assert(!(fBackendStatus & PDMAUDIOSTREAM_STS_INITIALIZED)); 3147 3350 RT_FALL_THRU(); … … 3151 3354 3152 3355 case DRVAUDIOPLAYSTATE_PREBUF_COMMITTING: 3356 Assert(pStreamEx->fStatus & PDMAUDIOSTREAM_STS_BACKEND_READY); 3357 Assert(fBackendStatus & PDMAUDIOSTREAM_STS_INITIALIZED); 3153 3358 rc = drvAudioStreamPreBufComitting(pThis, pStreamEx, (uint8_t const *)pvBuf, cbBuf, pcbWritten); 3154 3359 break; … … 3222 3427 if (pThis->In.fEnabled) /* Input for this audio driver enabled? See #9822. */ 3223 3428 { 3224 if (!PDMAudioStrmStatusCanRead(pStream ->fStatus))3429 if (!PDMAudioStrmStatusCanRead(pStreamEx->fStatus)) 3225 3430 { 3226 3431 rc = VERR_AUDIO_STREAM_NOT_READY; … … 3316 3521 * ... 3317 3522 */ 3318 AssertPtr(pThis->pHostDrvAudio->pfnStreamGetReadable);3319 3523 uint32_t cbReadable = pThis->pHostDrvAudio->pfnStreamGetReadable(pThis->pHostDrvAudio, pStreamEx->pBackend); 3320 3524 if (!cbReadable) … … 3494 3698 char szStreamSts[DRVAUDIO_STATUS_STR_MAX]; 3495 3699 #endif 3496 Log3Func(("[%s] fStatus=%s\n", pStreamEx->Core.szName, dbgAudioStreamStatusToStr(szStreamSts, pStreamEx-> Core.fStatus)));3700 Log3Func(("[%s] fStatus=%s\n", pStreamEx->Core.szName, dbgAudioStreamStatusToStr(szStreamSts, pStreamEx->fStatus))); 3497 3701 3498 3702 /* … … 3509 3713 3510 3714 if ( !pThis->In.fEnabled 3511 || !PDMAudioStrmStatusCanRead(pStreamEx->Core.fStatus)) 3715 || !PDMAudioStrmStatusCanRead(pStreamEx->fStatus) 3716 || !(pStreamEx->fStatus & PDMAUDIOSTREAM_STS_BACKEND_READY)) 3512 3717 { 3513 3718 rc = VERR_AUDIO_STREAM_NOT_READY; … … 3515 3720 } 3516 3721 3517 /* 3518 * Do the actual capturing. 3519 */ 3520 if (RT_LIKELY(pStreamEx->Host.Cfg.enmLayout == PDMAUDIOSTREAMLAYOUT_NON_INTERLEAVED)) 3521 rc = drvAudioStreamCaptureNonInterleaved(pThis, pStreamEx, &cfCaptured); 3522 else if (pStreamEx->Host.Cfg.enmLayout == PDMAUDIOSTREAMLAYOUT_RAW) 3523 rc = drvAudioStreamCaptureRaw(pThis, pStreamEx, &cfCaptured); 3722 uint32_t const fBackendStatus = drvAudioStreamGetBackendStatus(pThis, pStreamEx); 3723 if (fBackendStatus & PDMAUDIOSTREAM_STS_INITIALIZED) 3724 { 3725 /* 3726 * Do the actual capturing. 3727 */ 3728 if (RT_LIKELY(pStreamEx->Host.Cfg.enmLayout == PDMAUDIOSTREAMLAYOUT_NON_INTERLEAVED)) 3729 rc = drvAudioStreamCaptureNonInterleaved(pThis, pStreamEx, &cfCaptured); 3730 else if (pStreamEx->Host.Cfg.enmLayout == PDMAUDIOSTREAMLAYOUT_RAW) 3731 rc = drvAudioStreamCaptureRaw(pThis, pStreamEx, &cfCaptured); 3732 else 3733 AssertFailedStmt(rc = VERR_NOT_IMPLEMENTED); 3734 3735 if (RT_SUCCESS(rc)) 3736 { 3737 Log3Func(("[%s] %RU32 frames captured, rc=%Rrc\n", pStreamEx->Core.szName, cfCaptured, rc)); 3738 3739 STAM_COUNTER_ADD(&pThis->Stats.TotalFramesIn, cfCaptured); 3740 STAM_COUNTER_ADD(&pStreamEx->In.Stats.TotalFramesCaptured, cfCaptured); 3741 } 3742 else if (RT_UNLIKELY(RT_FAILURE(rc))) 3743 LogRel(("Audio: Capturing stream '%s' failed with %Rrc\n", pStreamEx->Core.szName, rc)); 3744 } 3524 3745 else 3525 AssertFailedStmt(rc = VERR_NOT_IMPLEMENTED); 3526 3527 if (RT_SUCCESS(rc)) 3528 { 3529 Log3Func(("[%s] %RU32 frames captured, rc=%Rrc\n", pStreamEx->Core.szName, cfCaptured, rc)); 3530 3531 STAM_COUNTER_ADD(&pThis->Stats.TotalFramesIn, cfCaptured); 3532 STAM_COUNTER_ADD(&pStreamEx->In.Stats.TotalFramesCaptured, cfCaptured); 3533 } 3534 else if (RT_UNLIKELY(RT_FAILURE(rc))) 3535 LogRel(("Audio: Capturing stream '%s' failed with %Rrc\n", pStreamEx->Core.szName, rc)); 3746 rc = VERR_AUDIO_STREAM_NOT_READY; 3536 3747 } while (0); 3537 3748 … … 3548 3759 3549 3760 /********************************************************************************************************************************* 3550 * PDMI AUDIONOTIFYFROMHOST interface implementation.*3761 * PDMIHOSTAUDIOPORT interface implementation. * 3551 3762 *********************************************************************************************************************************/ 3552 3763 3553 3764 /** 3765 * Worker for drvAudioHostPort_DoOnWorkerThread with stream argument, called on 3766 * worker thread. 3767 */ 3768 static DECLCALLBACK(void) drvAudioHostPort_DoOnWorkerThreadStreamWorker(PDRVAUDIO pThis, PDRVAUDIOSTREAM pStreamEx, 3769 uintptr_t uUser, void *pvUser) 3770 { 3771 LogFlowFunc(("pThis=%p uUser=%#zx pvUser=%p\n", pThis, uUser, pvUser)); 3772 AssertPtrReturnVoid(pThis); 3773 AssertPtrReturnVoid(pStreamEx); 3774 AssertReturnVoid(pStreamEx->uMagic == DRVAUDIOSTREAM_MAGIC); 3775 PPDMIHOSTAUDIO const pIHostDrvAudio = pThis->pHostDrvAudio; 3776 AssertPtrReturnVoid(pIHostDrvAudio); 3777 AssertPtrReturnVoid(pIHostDrvAudio->pfnDoOnWorkerThread); 3778 3779 pIHostDrvAudio->pfnDoOnWorkerThread(pIHostDrvAudio, pStreamEx->pBackend, uUser, pvUser); 3780 3781 drvAudioStreamReleaseInternal(pThis, pStreamEx, true /*fMayDestroy*/); 3782 LogFlowFunc(("returns\n")); 3783 } 3784 3785 3786 /** 3787 * Worker for drvAudioHostPort_DoOnWorkerThread without stream argument, called 3788 * on worker thread. 3789 * 3790 * This wrapper isn't technically required, but it helps with logging and a few 3791 * extra sanity checks. 3792 */ 3793 static DECLCALLBACK(void) drvAudioHostPort_DoOnWorkerThreadWorker(PDRVAUDIO pThis, uintptr_t uUser, void *pvUser) 3794 { 3795 LogFlowFunc(("pThis=%p uUser=%#zx pvUser=%p\n", pThis, uUser, pvUser)); 3796 AssertPtrReturnVoid(pThis); 3797 PPDMIHOSTAUDIO const pIHostDrvAudio = pThis->pHostDrvAudio; 3798 AssertPtrReturnVoid(pIHostDrvAudio); 3799 AssertPtrReturnVoid(pIHostDrvAudio->pfnDoOnWorkerThread); 3800 3801 pIHostDrvAudio->pfnDoOnWorkerThread(pIHostDrvAudio, NULL, uUser, pvUser); 3802 3803 LogFlowFunc(("returns\n")); 3804 } 3805 3806 3807 /** 3808 * @interface_method_impl{PDMIHOSTAUDIOPORT,pfnDoOnWorkerThread} 3809 */ 3810 static DECLCALLBACK(int) drvAudioHostPort_DoOnWorkerThread(PPDMIHOSTAUDIOPORT pInterface, PPDMAUDIOBACKENDSTREAM pStream, 3811 uintptr_t uUser, void *pvUser) 3812 { 3813 PDRVAUDIO pThis = RT_FROM_MEMBER(pInterface, DRVAUDIO, IHostAudioPort); 3814 LogFlowFunc(("pStream=%p uUser=%#zx pvUser=%p\n", pStream, uUser, pvUser)); 3815 3816 /* 3817 * Assert some sanity and do the work. 3818 */ 3819 AssertReturn(pThis->pHostDrvAudio, VERR_INTERNAL_ERROR_3); 3820 AssertReturn(pThis->pHostDrvAudio->pfnDoOnWorkerThread, VERR_INVALID_FUNCTION); 3821 AssertReturn(pThis->hReqPool != NIL_RTREQPOOL, VERR_INVALID_FUNCTION); 3822 int rc; 3823 if (!pStream) 3824 { 3825 rc = RTReqPoolCallEx(pThis->hReqPool, 0 /*cMillies*/, NULL /*phReq*/, RTREQFLAGS_VOID | RTREQFLAGS_NO_WAIT, 3826 (PFNRT)drvAudioHostPort_DoOnWorkerThreadWorker, 3, pThis, uUser, pvUser); 3827 AssertRC(rc); 3828 } 3829 else 3830 { 3831 AssertPtrReturn(pStream, VERR_INVALID_POINTER); 3832 AssertReturn(pStream->uMagic == PDMAUDIOBACKENDSTREAM_MAGIC, VERR_INVALID_MAGIC); 3833 PDRVAUDIOSTREAM pStreamEx = (PDRVAUDIOSTREAM)pStream->pStream; 3834 AssertPtrReturn(pStreamEx, VERR_INVALID_POINTER); 3835 AssertReturn(pStreamEx->uMagic == DRVAUDIOSTREAM_MAGIC, VERR_INVALID_MAGIC); 3836 AssertReturn(pStreamEx->Core.uMagic == PDMAUDIOSTREAM_MAGIC, VERR_INVALID_MAGIC); 3837 3838 uint32_t cRefs = drvAudioStreamRetainInternal(pStreamEx); 3839 if (cRefs != UINT32_MAX) 3840 { 3841 rc = RTReqPoolCallEx(pThis->hReqPool, 0 /*cMillies*/, NULL, RTREQFLAGS_VOID | RTREQFLAGS_NO_WAIT, 3842 (PFNRT)drvAudioHostPort_DoOnWorkerThreadStreamWorker, 3843 4, pThis, pStreamEx, uUser, pvUser); 3844 AssertRC(rc); 3845 if (RT_FAILURE(rc)) 3846 drvAudioStreamReleaseInternal(pThis, pStreamEx, true /*fMayDestroy*/); 3847 } 3848 else 3849 rc = VERR_INVALID_PARAMETER; 3850 } 3851 LogFlowFunc(("returns %Rrc\n", rc)); 3852 return rc; 3853 } 3854 3855 3856 /** 3554 3857 * Marks a stream for re-init. 3555 3858 */ … … 3557 3860 { 3558 3861 LogFlow((LOG_FN_FMT ": Flagging %s for re-init.\n", pszCaller, pStreamEx->Core.szName)); RT_NOREF(pszCaller); 3559 pStreamEx-> Core.fStatus|= PDMAUDIOSTREAM_STS_NEED_REINIT;3560 PDMAUDIOSTREAM_STS_ASSERT_VALID(pStreamEx-> Core.fStatus);3862 pStreamEx->fStatus |= PDMAUDIOSTREAM_STS_NEED_REINIT; 3863 PDMAUDIOSTREAM_STS_ASSERT_VALID(pStreamEx->fStatus); 3561 3864 pStreamEx->cTriesReInit = 0; 3562 3865 pStreamEx->nsLastReInit = 0; … … 3565 3868 3566 3869 /** 3567 * @interface_method_impl{PDMIAUDIONOTIFYFROMHOST,pfnNotifyDeviceChanged} 3568 */ 3569 static DECLCALLBACK(void) drvAudioNotifyFromHost_NotifyDeviceChanged(PPDMIAUDIONOTIFYFROMHOST pInterface, 3570 PDMAUDIODIR enmDir, void *pvUser) 3571 { 3572 PDRVAUDIO pThis = RT_FROM_MEMBER(pInterface, DRVAUDIO, IAudioNotifyFromHost); 3870 * @interface_method_impl{PDMIHOSTAUDIOPORT,pfnNotifyDeviceChanged} 3871 */ 3872 static DECLCALLBACK(void) drvAudioHostPort_NotifyDeviceChanged(PPDMIHOSTAUDIOPORT pInterface, PDMAUDIODIR enmDir, void *pvUser) 3873 { 3874 PDRVAUDIO pThis = RT_FROM_MEMBER(pInterface, DRVAUDIO, IHostAudioPort); 3573 3875 AssertReturnVoid(enmDir == PDMAUDIODIR_IN || enmDir == PDMAUDIODIR_OUT); 3574 3876 LogRel(("Audio: The %s device for %s is changing.\n", enmDir == PDMAUDIODIR_IN ? "input" : "output", pThis->szName)); … … 3596 3898 3597 3899 /** 3598 * @interface_method_impl{PDMI AUDIONOTIFYFROMHOST,pfnStreamNotifyDeviceChanged}3599 */ 3600 static DECLCALLBACK(void) drvAudio NotifyFromHost_StreamNotifyDeviceChanged(PPDMIAUDIONOTIFYFROMHOST pInterface,3601 3602 { 3603 PDRVAUDIO pThis = RT_FROM_MEMBER(pInterface, DRVAUDIO, I AudioNotifyFromHost);3900 * @interface_method_impl{PDMIHOSTAUDIOPORT,pfnStreamNotifyDeviceChanged} 3901 */ 3902 static DECLCALLBACK(void) drvAudioHostPort_StreamNotifyDeviceChanged(PPDMIHOSTAUDIOPORT pInterface, 3903 PPDMAUDIOBACKENDSTREAM pStream, bool fReInit) 3904 { 3905 PDRVAUDIO pThis = RT_FROM_MEMBER(pInterface, DRVAUDIO, IHostAudioPort); 3604 3906 3605 3907 /* … … 3630 3932 * know which thread we're on, do we now). 3631 3933 */ 3632 AssertStmt(!(pStreamEx-> Core.fStatus & PDMAUDIOSTREAM_STS_NEED_REINIT),3633 pStreamEx-> Core.fStatus &= ~PDMAUDIOSTREAM_STS_NEED_REINIT);3934 AssertStmt(!(pStreamEx->fStatus & PDMAUDIOSTREAM_STS_NEED_REINIT), 3935 pStreamEx->fStatus &= ~PDMAUDIOSTREAM_STS_NEED_REINIT); 3634 3936 3635 3937 if ( pStreamEx->Core.enmDir == PDMAUDIODIR_OUT 3636 && (pStreamEx-> Core.fStatus & PDMAUDIOSTREAM_STS_ENABLED))3938 && (pStreamEx->fStatus & PDMAUDIOSTREAM_STS_ENABLED)) 3637 3939 { 3638 3940 DRVAUDIOPLAYSTATE const enmPlayState = pStreamEx->Out.enmPlayState; … … 3648 3950 3649 3951 /** 3650 * @interface_method_impl{PDMI AUDIONOTIFYFROMHOST,pfnNotifyDevicesChanged}3651 */ 3652 static DECLCALLBACK(void) drvAudio NotifyFromHost_NotifyDevicesChanged(PPDMIAUDIONOTIFYFROMHOST pInterface)3653 { 3654 PDRVAUDIO pThis = RT_FROM_MEMBER(pInterface, DRVAUDIO, I AudioNotifyFromHost);3952 * @interface_method_impl{PDMIHOSTAUDIOPORT,pfnNotifyDevicesChanged} 3953 */ 3954 static DECLCALLBACK(void) drvAudioHostPort_NotifyDevicesChanged(PPDMIHOSTAUDIOPORT pInterface) 3955 { 3956 PDRVAUDIO pThis = RT_FROM_MEMBER(pInterface, DRVAUDIO, IHostAudioPort); 3655 3957 LogRel(("Audio: Device configuration of driver '%s' has changed\n", pThis->szName)); 3656 3958 … … 3690 3992 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase); 3691 3993 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIAUDIOCONNECTOR, &pThis->IAudioConnector); 3692 PDMIBASE_RETURN_INTERFACE(pszIID, PDMI AUDIONOTIFYFROMHOST, &pThis->IAudioNotifyFromHost);3994 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHOSTAUDIOPORT, &pThis->IHostAudioPort); 3693 3995 3694 3996 return NULL; … … 3723 4025 { 3724 4026 drvAudioStreamControlInternalBackend(pThis, pStreamEx, PDMAUDIOSTREAMCMD_DISABLE); 4027 #if 0 /* This leads to double destruction. Also in the backend when we don't set pHostDrvAudio to NULL below. */ 3725 4028 drvAudioStreamDestroyInternalBackend(pThis, pStreamEx); 3726 } 3727 4029 #endif 4030 } 4031 4032 #if 0 /* Messes up using drvAudioHostPort_DoOnWorkerThread from the backend drivers' power off callback. */ 3728 4033 pThis->pHostDrvAudio = NULL; 4034 #endif 3729 4035 } 3730 4036 … … 3748 4054 AssertRC(rc); 3749 4055 3750 LogFunc(("%s (detached %p)\n", pThis->szName, pThis->pHostDrvAudio)); 4056 LogFunc(("%s (detached %p, hReqPool=%p)\n", pThis->szName, pThis->pHostDrvAudio, pThis->hReqPool)); 4057 4058 /* 4059 * Must first destroy the thread pool first so we are certain no threads 4060 * are still using the instance being detached. Release lock while doing 4061 * this as the thread functions may need to take it to complete. 4062 */ 4063 if (pThis->pHostDrvAudio && pThis->hReqPool != NIL_RTREQPOOL) 4064 { 4065 RTREQPOOL hReqPool = pThis->hReqPool; 4066 pThis->hReqPool = NIL_RTREQPOOL; 4067 RTCritSectLeave(&pThis->CritSect); 4068 4069 RTReqPoolRelease(hReqPool); 4070 4071 RTCritSectEnter(&pThis->CritSect); 4072 } 4073 4074 /* 4075 * Now we can safely set pHostDrvAudio to NULL. 4076 */ 3751 4077 pThis->pHostDrvAudio = NULL; 3752 4078 … … 3769 4095 * mandatory are present. 3770 4096 */ 3771 PPDMIHOSTAUDIO pHostDrvAudio = pThis->pHostDrvAudio; 3772 AssertPtrReturn(pHostDrvAudio, VERR_INVALID_POINTER); 3773 AssertPtrReturn(pHostDrvAudio->pfnGetConfig, VERR_INVALID_POINTER); 3774 AssertPtrNullReturn(pHostDrvAudio->pfnGetDevices, VERR_INVALID_POINTER); 3775 AssertPtrNullReturn(pHostDrvAudio->pfnGetStatus, VERR_INVALID_POINTER); 3776 AssertPtrNullReturn(pHostDrvAudio->pfnStreamConfigHint, VERR_INVALID_POINTER); 3777 AssertPtrReturn(pHostDrvAudio->pfnStreamCreate, VERR_INVALID_POINTER); 3778 AssertPtrReturn(pHostDrvAudio->pfnStreamDestroy, VERR_INVALID_POINTER); 3779 AssertPtrNullReturn(pHostDrvAudio->pfnStreamNotifyDeviceChanged, VERR_INVALID_POINTER); 3780 AssertPtrReturn(pHostDrvAudio->pfnStreamControl, VERR_INVALID_POINTER); 3781 AssertPtrReturn(pHostDrvAudio->pfnStreamGetReadable, VERR_INVALID_POINTER); 3782 AssertPtrReturn(pHostDrvAudio->pfnStreamGetWritable, VERR_INVALID_POINTER); 3783 AssertPtrNullReturn(pHostDrvAudio->pfnStreamGetPending, VERR_INVALID_POINTER); 3784 AssertPtrReturn(pHostDrvAudio->pfnStreamGetStatus, VERR_INVALID_POINTER); 3785 AssertPtrReturn(pHostDrvAudio->pfnStreamPlay, VERR_INVALID_POINTER); 3786 AssertPtrReturn(pHostDrvAudio->pfnStreamCapture, VERR_INVALID_POINTER); 4097 PPDMIHOSTAUDIO pIHostDrvAudio = pThis->pHostDrvAudio; 4098 AssertPtrReturn(pIHostDrvAudio, VERR_INVALID_POINTER); 4099 AssertPtrReturn(pIHostDrvAudio->pfnGetConfig, VERR_INVALID_POINTER); 4100 AssertPtrNullReturn(pIHostDrvAudio->pfnGetDevices, VERR_INVALID_POINTER); 4101 AssertPtrNullReturn(pIHostDrvAudio->pfnGetStatus, VERR_INVALID_POINTER); 4102 AssertPtrNullReturn(pIHostDrvAudio->pfnDoOnWorkerThread, VERR_INVALID_POINTER); 4103 AssertPtrNullReturn(pIHostDrvAudio->pfnStreamConfigHint, VERR_INVALID_POINTER); 4104 AssertPtrReturn(pIHostDrvAudio->pfnStreamCreate, VERR_INVALID_POINTER); 4105 AssertPtrNullReturn(pIHostDrvAudio->pfnStreamInitAsync, VERR_INVALID_POINTER); 4106 AssertPtrReturn(pIHostDrvAudio->pfnStreamDestroy, VERR_INVALID_POINTER); 4107 AssertPtrNullReturn(pIHostDrvAudio->pfnStreamNotifyDeviceChanged, VERR_INVALID_POINTER); 4108 AssertPtrReturn(pIHostDrvAudio->pfnStreamControl, VERR_INVALID_POINTER); 4109 AssertPtrReturn(pIHostDrvAudio->pfnStreamGetReadable, VERR_INVALID_POINTER); 4110 AssertPtrReturn(pIHostDrvAudio->pfnStreamGetWritable, VERR_INVALID_POINTER); 4111 AssertPtrNullReturn(pIHostDrvAudio->pfnStreamGetPending, VERR_INVALID_POINTER); 4112 AssertPtrReturn(pIHostDrvAudio->pfnStreamGetStatus, VERR_INVALID_POINTER); 4113 AssertPtrReturn(pIHostDrvAudio->pfnStreamPlay, VERR_INVALID_POINTER); 4114 AssertPtrReturn(pIHostDrvAudio->pfnStreamCapture, VERR_INVALID_POINTER); 3787 4115 3788 4116 /* 3789 4117 * Get the backend configuration. 3790 4118 */ 3791 int rc = p This->pHostDrvAudio->pfnGetConfig(pThis->pHostDrvAudio, &pThis->BackendCfg);4119 int rc = pIHostDrvAudio->pfnGetConfig(pIHostDrvAudio, &pThis->BackendCfg); 3792 4120 if (RT_FAILURE(rc)) 3793 4121 { … … 3808 4136 if (rc2 != VERR_NOT_SUPPORTED) /* Some backends don't implement device enumeration. */ 3809 4137 AssertRC(rc2); 3810 3811 RT_NOREF(rc2); 3812 /* Ignore rc. */ 4138 /* Ignore rc2. */ 3813 4139 #endif 4140 4141 /* 4142 * Create a thread pool if stream creation can be asynchronous. 4143 * 4144 * The pool employs no pushback as the caller is typically EMT and 4145 * shouldn't be delayed. 4146 * 4147 * The number of threads limits and the device implementations use 4148 * of pfnStreamDestroy limits the number of streams pending async 4149 * init. We use RTReqCancel in drvAudioStreamDestroy to allow us 4150 * to release extra reference held by the pfnStreamInitAsync call 4151 * if successful. Cancellation will only be possible if the call 4152 * hasn't been picked up by a worker thread yet, so the max number 4153 * of threads in the pool defines how many destroyed streams that 4154 * can be lingering. (We must keep this under control, otherwise 4155 * an evil guest could just rapidly trigger stream creation and 4156 * destruction to consume host heap and hog CPU resources for 4157 * configuring audio backends.) 4158 */ 4159 if ( pThis->hReqPool == NIL_RTREQPOOL 4160 && ( pIHostDrvAudio->pfnStreamInitAsync 4161 || pIHostDrvAudio->pfnDoOnWorkerThread 4162 || (pThis->BackendCfg.fFlags & PDMAUDIOBACKEND_F_ASYNC_HINT) )) 4163 { 4164 char szName[16]; 4165 RTStrPrintf(szName, sizeof(szName), "Aud%uWr", pThis->pDrvIns->iInstance); 4166 RTREQPOOL hReqPool = NIL_RTREQPOOL; 4167 rc = RTReqPoolCreate(3 /*cMaxThreads*/, RT_MS_30SEC /*cMsMinIdle*/, UINT32_MAX /*cThreadsPushBackThreshold*/, 4168 1 /*cMsMaxPushBack*/, szName, &hReqPool); 4169 LogFlowFunc(("Creating thread pool '%s': %Rrc, hReqPool=%p\n", szName, rc, hReqPool)); 4170 AssertRCReturn(rc, rc); 4171 4172 rc = RTReqPoolSetCfgVar(hReqPool, RTREQPOOLCFGVAR_THREAD_FLAGS, RTTHREADFLAGS_COM_MTA); 4173 AssertRCReturnStmt(rc, RTReqPoolRelease(hReqPool), rc); 4174 4175 rc = RTReqPoolSetCfgVar(hReqPool, RTREQPOOLCFGVAR_MIN_THREADS, 1); 4176 AssertRC(rc); /* harmless */ 4177 4178 pThis->hReqPool = hReqPool; 4179 } 4180 else 4181 LogFlowFunc(("No thread pool.\n")); 3814 4182 3815 4183 LogFlowFuncLeave(); … … 4022 4390 #endif 4023 4391 4392 if (pThis->hReqPool != NIL_RTREQPOOL) 4393 { 4394 uint32_t cRefs = RTReqPoolRelease(pThis->hReqPool); 4395 Assert(cRefs == 0); RT_NOREF(cRefs); 4396 pThis->hReqPool = NIL_RTREQPOOL; 4397 } 4398 4024 4399 LogFlowFuncLeave(); 4025 4400 } … … 4041 4416 */ 4042 4417 RTListInit(&pThis->lstStreams); 4418 pThis->hReqPool = NIL_RTREQPOOL; 4043 4419 4044 4420 /* … … 4221 4597 pThis->IAudioConnector.pfnStreamRead = drvAudioStreamRead; 4222 4598 pThis->IAudioConnector.pfnStreamCapture = drvAudioStreamCapture; 4223 /* IAudioNotifyFromHost */ 4224 pThis->IAudioNotifyFromHost.pfnNotifyDeviceChanged = drvAudioNotifyFromHost_NotifyDeviceChanged; 4225 pThis->IAudioNotifyFromHost.pfnStreamNotifyDeviceChanged = drvAudioNotifyFromHost_StreamNotifyDeviceChanged; 4226 pThis->IAudioNotifyFromHost.pfnNotifyDevicesChanged = drvAudioNotifyFromHost_NotifyDevicesChanged; 4599 /* IHostAudioPort */ 4600 pThis->IHostAudioPort.pfnDoOnWorkerThread = drvAudioHostPort_DoOnWorkerThread; 4601 pThis->IHostAudioPort.pfnNotifyDeviceChanged = drvAudioHostPort_NotifyDeviceChanged; 4602 pThis->IHostAudioPort.pfnStreamNotifyDeviceChanged = drvAudioHostPort_StreamNotifyDeviceChanged; 4603 pThis->IHostAudioPort.pfnNotifyDevicesChanged = drvAudioHostPort_NotifyDevicesChanged; 4227 4604 4228 4605 /* -
trunk/src/VBox/Devices/Audio/DrvHostAudioAlsa.cpp
r88761 r88819 1408 1408 pThis->IHostAudio.pfnGetDevices = drvHostAlsaAudioHA_GetDevices; 1409 1409 pThis->IHostAudio.pfnGetStatus = drvHostAlsaAudioHA_GetStatus; 1410 pThis->IHostAudio.pfnDoOnWorkerThread = NULL; 1411 pThis->IHostAudio.pfnStreamConfigHint = NULL; 1410 1412 pThis->IHostAudio.pfnStreamCreate = drvHostAlsaAudioHA_StreamCreate; 1413 pThis->IHostAudio.pfnStreamInitAsync = NULL; 1411 1414 pThis->IHostAudio.pfnStreamDestroy = drvHostAlsaAudioHA_StreamDestroy; 1412 1415 pThis->IHostAudio.pfnStreamNotifyDeviceChanged = NULL; -
trunk/src/VBox/Devices/Audio/DrvHostAudioCoreAudio.cpp
r88761 r88819 2547 2547 pThis->IHostAudio.pfnGetConfig = drvHostCoreAudioHA_GetConfig; 2548 2548 pThis->IHostAudio.pfnGetStatus = drvHostCoreAudioHA_GetStatus; 2549 pThis->IHostAudio.pfnDoOnWorkerThread = NULL; 2550 pThis->IHostAudio.pfnStreamConfigHint = NULL; 2549 2551 pThis->IHostAudio.pfnStreamCreate = drvHostCoreAudioHA_StreamCreate; 2552 pThis->IHostAudio.pfnStreamInitAsync = NULL; 2550 2553 pThis->IHostAudio.pfnStreamDestroy = drvHostCoreAudioHA_StreamDestroy; 2551 2554 pThis->IHostAudio.pfnStreamNotifyDeviceChanged = NULL; -
trunk/src/VBox/Devices/Audio/DrvHostAudioDSound.cpp
r88761 r88819 2761 2761 pThis->IHostAudio.pfnGetDevices = drvHostDSoundHA_GetDevices; 2762 2762 pThis->IHostAudio.pfnGetStatus = drvHostDSoundHA_GetStatus; 2763 pThis->IHostAudio.pfnDoOnWorkerThread = NULL; 2764 pThis->IHostAudio.pfnStreamConfigHint = NULL; 2763 2765 pThis->IHostAudio.pfnStreamCreate = drvHostDSoundHA_StreamCreate; 2766 pThis->IHostAudio.pfnStreamInitAsync = NULL; 2764 2767 pThis->IHostAudio.pfnStreamDestroy = drvHostDSoundHA_StreamDestroy; 2765 2768 pThis->IHostAudio.pfnStreamNotifyDeviceChanged = NULL; … … 2801 2804 /* Get the notification interface (from DrvAudio). */ 2802 2805 # ifdef VBOX_WITH_AUDIO_CALLBACKS 2803 PPDMI AUDIONOTIFYFROMHOST pIAudioNotifyFromHost = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIAUDIONOTIFYFROMHOST);2804 Assert(pI AudioNotifyFromHost);2806 PPDMIHOSTAUDIOPORT pIHostAudioPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIHOSTAUDIOPORT); 2807 Assert(pIHostAudioPort); 2805 2808 # else 2806 PPDMI AUDIONOTIFYFROMHOST pIAudioNotifyFromHost = NULL;2809 PPDMIHOSTAUDIOPORT pIHostAudioPort = NULL; 2807 2810 # endif 2808 2811 try 2809 2812 { 2810 pThis->m_pNotificationClient = new DrvHostAudioDSoundMMNotifClient(pI AudioNotifyFromHost);2813 pThis->m_pNotificationClient = new DrvHostAudioDSoundMMNotifClient(pIHostAudioPort); 2811 2814 } 2812 2815 catch (std::bad_alloc &) -
trunk/src/VBox/Devices/Audio/DrvHostAudioDSoundMMNotifClient.cpp
r88361 r88819 30 30 31 31 32 DrvHostAudioDSoundMMNotifClient::DrvHostAudioDSoundMMNotifClient(PPDMI AUDIONOTIFYFROMHOST pInterface)32 DrvHostAudioDSoundMMNotifClient::DrvHostAudioDSoundMMNotifClient(PPDMIHOSTAUDIOPORT pInterface) 33 33 : m_fRegisteredClient(false) 34 34 , m_cRef(1) -
trunk/src/VBox/Devices/Audio/DrvHostAudioDSoundMMNotifClient.h
r88628 r88819 43 43 public: 44 44 45 DrvHostAudioDSoundMMNotifClient(PPDMI AUDIONOTIFYFROMHOST pInterface);45 DrvHostAudioDSoundMMNotifClient(PPDMIHOSTAUDIOPORT pInterface); 46 46 virtual ~DrvHostAudioDSoundMMNotifClient(); 47 47 … … 64 64 long m_cRef; 65 65 66 PPDMI AUDIONOTIFYFROMHOSTm_pIAudioNotifyFromHost;66 PPDMIHOSTAUDIOPORT m_pIAudioNotifyFromHost; 67 67 68 68 HRESULT AttachToDefaultEndpoint(); -
trunk/src/VBox/Devices/Audio/DrvHostAudioDebug.cpp
r88761 r88819 438 438 pThis->IHostAudio.pfnGetDevices = NULL; 439 439 pThis->IHostAudio.pfnGetStatus = drvHostDebugAudioHA_GetStatus; 440 pThis->IHostAudio.pfnDoOnWorkerThread = NULL; 441 pThis->IHostAudio.pfnStreamConfigHint = NULL; 440 442 pThis->IHostAudio.pfnStreamCreate = drvHostDebugAudioHA_StreamCreate; 443 pThis->IHostAudio.pfnStreamInitAsync = NULL; 441 444 pThis->IHostAudio.pfnStreamDestroy = drvHostDebugAudioHA_StreamDestroy; 442 445 pThis->IHostAudio.pfnStreamNotifyDeviceChanged = NULL; -
trunk/src/VBox/Devices/Audio/DrvHostAudioNull.cpp
r88760 r88819 232 232 /* .pfnGetDevices =*/ NULL, 233 233 /* .pfnGetStatus =*/ drvHostNullAudioHA_GetStatus, 234 /* .pfnDoOnWorkerThread =*/ NULL, 234 235 /* .pfnStreamConfigHint =*/ NULL, 235 236 /* .pfnStreamCreate =*/ drvHostNullAudioHA_StreamCreate, 237 /* .pfnStreamInitAsync =*/ NULL, 236 238 /* .pfnStreamDestroy =*/ drvHostNullAudioHA_StreamDestroy, 237 239 /* .pfnStreamNotifyDeviceChanged =*/ NULL, -
trunk/src/VBox/Devices/Audio/DrvHostAudioOss.cpp
r88761 r88819 861 861 pThis->IHostAudio.pfnGetDevices = NULL; 862 862 pThis->IHostAudio.pfnGetStatus = drvHostOssAudioHA_GetStatus; 863 pThis->IHostAudio.pfnDoOnWorkerThread = NULL; 864 pThis->IHostAudio.pfnStreamConfigHint = NULL; 863 865 pThis->IHostAudio.pfnStreamCreate = drvHostOssAudioHA_StreamCreate; 866 pThis->IHostAudio.pfnStreamInitAsync = NULL; 864 867 pThis->IHostAudio.pfnStreamDestroy = drvHostOssAudioHA_StreamDestroy; 865 868 pThis->IHostAudio.pfnStreamNotifyDeviceChanged = NULL; -
trunk/src/VBox/Devices/Audio/DrvHostAudioPulseAudio.cpp
r88761 r88819 1915 1915 pThis->IHostAudio.pfnGetDevices = drvHostAudioPaHA_GetDevices; 1916 1916 pThis->IHostAudio.pfnGetStatus = drvHostAudioPaHA_GetStatus; 1917 pThis->IHostAudio.pfnDoOnWorkerThread = NULL; 1918 pThis->IHostAudio.pfnStreamConfigHint = NULL; 1917 1919 pThis->IHostAudio.pfnStreamCreate = drvHostAudioPaHA_StreamCreate; 1920 pThis->IHostAudio.pfnStreamInitAsync = NULL; 1918 1921 pThis->IHostAudio.pfnStreamDestroy = drvHostAudioPaHA_StreamDestroy; 1919 1922 pThis->IHostAudio.pfnStreamNotifyDeviceChanged = NULL; -
trunk/src/VBox/Devices/Audio/DrvHostAudioValidationKit.cpp
r88761 r88819 435 435 pThis->IHostAudio.pfnGetDevices = NULL; 436 436 pThis->IHostAudio.pfnGetStatus = drvHostValKitAudioHA_GetStatus; 437 pThis->IHostAudio.pfnDoOnWorkerThread = NULL; 438 pThis->IHostAudio.pfnStreamConfigHint = NULL; 437 439 pThis->IHostAudio.pfnStreamCreate = drvHostValKitAudioHA_StreamCreate; 440 pThis->IHostAudio.pfnStreamInitAsync = NULL; 438 441 pThis->IHostAudio.pfnStreamDestroy = drvHostValKitAudioHA_StreamDestroy; 439 442 pThis->IHostAudio.pfnStreamNotifyDeviceChanged = NULL; -
trunk/src/VBox/Devices/Audio/DrvHostAudioWasApi.cpp
r88776 r88819 53 53 #define VBOX_WASAPI_MAX_PADDING UINT32_C(0x007fffff) 54 54 55 #if 0 55 56 /** @name WM_DRVHOSTAUDIOWAS_XXX - Worker thread messages. 56 57 * @{ */ 57 /** Adds entry to the cache. 58 * lParam points to a PDMAUDIOSTREAMCFG structure with the details. RTMemFree 59 * when done. */ 60 #define WM_DRVHOSTAUDIOWAS_HINT (WM_APP + 2) 61 #define WM_DRVHOSTAUDIOWAS_PURGE_CACHE (WM_APP + 1) 58 #define WM_DRVHOSTAUDIOWAS_PURGE_CACHE (WM_APP + 3) 59 /** @} */ 60 #endif 61 62 63 /** @name DRVHOSTAUDIOWAS_DO_XXX - Worker thread operations. 64 * @{ */ 65 #define DRVHOSTAUDIOWAS_DO_PURGE_CACHE ((uintptr_t)0x49f37300 + 1) 62 66 /** @} */ 63 67 … … 100 104 /** The device/whatever period in frames. */ 101 105 uint32_t cFramesPeriod; 106 /** The setup status code. 107 * This is set to VERR_AUDIO_STREAM_INIT_IN_PROGRESS while the asynchronous 108 * initialization is still running. */ 109 int volatile rcSetup; 110 /** Creation timestamp (just for reference). */ 111 uint64_t nsCreated; 112 /** Init complete timestamp (just for reference). */ 113 uint64_t nsInited; 102 114 /** The stringified properties. */ 103 115 char szProps[32]; … … 207 219 * implementing enumeration. */ 208 220 IMMDeviceEnumerator *pIEnumerator; 209 /** Notification interface.*/210 PPDMI AUDIONOTIFYFROMHOST pIAudioNotifyFromHost;221 /** The upwards interface. */ 222 PPDMIHOSTAUDIOPORT pIHostAudioPort; 211 223 /** The output device ID, NULL for default. */ 212 224 PRTUTF16 pwszOutputDevId; … … 240 252 RTCRITSECT CritSectCache; 241 253 254 #if 0 242 255 /** The worker thread. */ 243 256 RTTHREAD hWorkerThread; … … 246 259 /** The fixed wParam value for the worker thread. */ 247 260 WPARAM uWorkerThreadFixedParam; 248 261 #endif 249 262 } DRVHOSTAUDIOWAS; 250 263 /** Pointer to the data for a WASAPI host audio driver instance. */ … … 273 286 static RTSTRTUPLE const s_aStarted[2] = 274 287 { 275 RT_STR_TUPLE(" ST ARTED"),276 RT_STR_TUPLE(" ST OPPED")288 RT_STR_TUPLE(" STOPPED"), 289 RT_STR_TUPLE(" STARTED") 277 290 }; 278 291 pTuple = &s_aStarted[pStreamWas->fStarted]; … … 549 562 * Converts from PDM stream config to windows WAVEFORMATEX struct. 550 563 * 551 * @param p Cfg The PDM audio stream configto convert from.564 * @param pProps The PDM audio PCM properties to convert from. 552 565 * @param pFmt The windows structure to initialize. 553 566 */ 554 static void drvHostAudioWasWaveFmtExFrom Cfg(PCPDMAUDIOSTREAMCFG pCfg, PWAVEFORMATEX pFmt)567 static void drvHostAudioWasWaveFmtExFromProps(PCPDMAUDIOPCMPROPS pProps, PWAVEFORMATEX pFmt) 555 568 { 556 569 RT_ZERO(*pFmt); 557 570 pFmt->wFormatTag = WAVE_FORMAT_PCM; 558 pFmt->nChannels = PDMAudioPropsChannels( &pCfg->Props);559 pFmt->wBitsPerSample = PDMAudioPropsSampleBits( &pCfg->Props);560 pFmt->nSamplesPerSec = PDMAudioPropsHz( &pCfg->Props);561 pFmt->nBlockAlign = PDMAudioPropsFrameSize( &pCfg->Props);562 pFmt->nAvgBytesPerSec = PDMAudioPropsFramesToBytes( &pCfg->Props, PDMAudioPropsHz(&pCfg->Props));571 pFmt->nChannels = PDMAudioPropsChannels(pProps); 572 pFmt->wBitsPerSample = PDMAudioPropsSampleBits(pProps); 573 pFmt->nSamplesPerSec = PDMAudioPropsHz(pProps); 574 pFmt->nBlockAlign = PDMAudioPropsFrameSize(pProps); 575 pFmt->nAvgBytesPerSec = PDMAudioPropsFramesToBytes(pProps, PDMAudioPropsHz(pProps)); 563 576 pFmt->cbSize = 0; /* No extra data specified. */ 564 577 } 565 578 566 579 580 #if 0 /* unused */ 567 581 /** 568 582 * Converts from windows WAVEFORMATEX and stream props to PDM audio properties. … … 607 621 return VERR_AUDIO_STREAM_COULD_NOT_CREATE; 608 622 } 623 #endif 609 624 610 625 … … 714 729 } 715 730 716 /** 717 * Creates a device config entry using the given parameters. 731 732 /** 733 * Initializes a device config entry. 718 734 * 719 * Th e entry is not added to the cache but returned.735 * This is usually done on the worker thread. 720 736 * 721 * @returns Pointer to the new device config entry. NULL on failure. 722 * @param pDevEntry The device entry it belongs to. 723 * @param pCfgReq The requested configuration. 724 * @param pWaveFmtEx The actual configuration. 725 * @param pIAudioClient The audio client, reference consumed. 726 */ 727 static PDRVHOSTAUDIOWASCACHEDEVCFG 728 drvHostAudioWasCacheCreateConfig(PDRVHOSTAUDIOWASCACHEDEV pDevEntry, PCPDMAUDIOSTREAMCFG pCfgReq, 729 WAVEFORMATEX const *pWaveFmtEx, IAudioClient *pIAudioClient) 730 { 731 PDRVHOSTAUDIOWASCACHEDEVCFG pDevCfg = (PDRVHOSTAUDIOWASCACHEDEVCFG)RTMemAllocZ(sizeof(*pDevCfg)); 732 if (pDevCfg) 733 { 734 RTListInit(&pDevCfg->ListEntry); 735 pDevCfg->pDevEntry = pDevEntry; 736 pDevCfg->pIAudioClient = pIAudioClient; 737 HRESULT hrc; 738 if (pCfgReq->enmDir == PDMAUDIODIR_IN) 739 hrc = pIAudioClient->GetService(__uuidof(IAudioCaptureClient), (void **)&pDevCfg->pIAudioCaptureClient); 740 else 741 hrc = pIAudioClient->GetService(__uuidof(IAudioRenderClient), (void **)&pDevCfg->pIAudioRenderClient); 742 Log8Func(("GetService -> %Rhrc + %p\n", hrc, pCfgReq->enmDir == PDMAUDIODIR_IN 743 ? (void *)pDevCfg->pIAudioCaptureClient : (void *)pDevCfg->pIAudioRenderClient)); 744 if (SUCCEEDED(hrc)) 745 { 746 /* 747 * Obtain the actual stream format and buffer config. 748 * (A bit ugly structure here to keep it from hitting the right margin. Sorry.) 749 */ 750 UINT32 cFramesBufferSize = 0; 751 REFERENCE_TIME cDefaultPeriodInNtTicks = 0; 752 REFERENCE_TIME cMinimumPeriodInNtTicks = 0; 753 REFERENCE_TIME cLatencyinNtTicks = 0; 754 hrc = pIAudioClient->GetBufferSize(&cFramesBufferSize); 755 if (SUCCEEDED(hrc)) 756 hrc = pIAudioClient->GetDevicePeriod(&cDefaultPeriodInNtTicks, &cMinimumPeriodInNtTicks); 757 else 758 LogRelMax(64, ("WasAPI: GetBufferSize failed: %Rhrc\n", hrc)); 759 if (SUCCEEDED(hrc)) 760 hrc = pIAudioClient->GetStreamLatency(&cLatencyinNtTicks); 761 else 762 LogRelMax(64, ("WasAPI: GetDevicePeriod failed: %Rhrc\n", hrc)); 763 if (SUCCEEDED(hrc)) 764 { 765 LogRel2(("WasAPI: Aquired buffer parameters for %s:\n" 766 "WasAPI: cFramesBufferSize = %RU32\n" 767 "WasAPI: cDefaultPeriodInNtTicks = %RI64\n" 768 "WasAPI: cMinimumPeriodInNtTicks = %RI64\n" 769 "WasAPI: cLatencyinNtTicks = %RI64\n", 770 pCfgReq->szName, cFramesBufferSize, cDefaultPeriodInNtTicks, cMinimumPeriodInNtTicks, cLatencyinNtTicks)); 771 772 int rc = drvHostAudioWasCacheWaveFmtExToProps(&pDevCfg->Props, pWaveFmtEx, pCfgReq->szName, pDevEntry->wszDevId); 773 if (RT_SUCCESS(rc)) 774 { 775 pDevCfg->cFramesBufferSize = cFramesBufferSize; 776 pDevCfg->cFramesPeriod = PDMAudioPropsNanoToFrames(&pDevCfg->Props, cDefaultPeriodInNtTicks * 100); 777 778 PDMAudioPropsToString(&pDevCfg->Props, pDevCfg->szProps, sizeof(pDevCfg->szProps)); 779 return pDevCfg; 780 } 781 } 782 else 783 LogRelMax(64, ("WasAPI: GetStreamLatency failed: %Rhrc\n", hrc)); 784 785 if (pDevCfg->pIAudioCaptureClient) 786 { 787 pDevCfg->pIAudioCaptureClient->Release(); 788 pDevCfg->pIAudioCaptureClient = NULL; 789 } 790 791 if (pDevCfg->pIAudioRenderClient) 792 { 793 pDevCfg->pIAudioRenderClient->Release(); 794 pDevCfg->pIAudioRenderClient = NULL; 795 } 796 } 797 RTMemFree(pDevCfg); 798 } 799 pIAudioClient->Release(); 800 return NULL; 801 } 802 803 804 /** 805 * Worker for drvHostAudioWasCacheLookupOrCreate. 806 * 807 * If lookup fails, a new entry will be created. 808 * 809 * @note Called holding the lock, returning without holding it! 810 */ 811 static PDRVHOSTAUDIOWASCACHEDEVCFG 812 drvHostAudioWasCacheLookupOrCreateConfig(PDRVHOSTAUDIOWAS pThis, PDRVHOSTAUDIOWASCACHEDEV pDevEntry, PCPDMAUDIOSTREAMCFG pCfgReq) 813 { 814 char szProps[64]; 815 PDMAudioPropsToString(&pCfgReq->Props, szProps, sizeof(szProps)); 816 817 /* 818 * Check if we've got a matching config. 819 */ 820 PDRVHOSTAUDIOWASCACHEDEVCFG pDevCfg = drvHostAudioWasCacheLookupLocked(pDevEntry, &pCfgReq->Props); 821 if (pDevCfg) 822 { 823 RTCritSectLeave(&pThis->CritSectCache); 824 Log8Func(("Config cache hit '%s' (for '%s') on '%ls': %p\n", pDevCfg->szProps, szProps, pDevEntry->wszDevId, pDevCfg)); 825 return pDevCfg; 826 } 827 828 /* 829 * We now need an IAudioClient interface for calling IsFormatSupported 737 * @returns VBox status code. 738 * @param pDevCfg The device configuration entry to initialize. 739 */ 740 static int drvHostAudioWasCacheInitConfig(PDRVHOSTAUDIOWASCACHEDEVCFG pDevCfg) 741 { 742 /* 743 * Assert some sanity given that we migth be called on the worker thread 744 * and pDevCfg being a message parameter. 745 */ 746 AssertPtrReturn(pDevCfg, VERR_INTERNAL_ERROR_2); 747 AssertReturn(pDevCfg->rcSetup == VERR_AUDIO_STREAM_INIT_IN_PROGRESS, VERR_INTERNAL_ERROR_2); 748 AssertReturn(pDevCfg->pIAudioClient == NULL, VERR_INTERNAL_ERROR_2); 749 AssertReturn(pDevCfg->pIAudioCaptureClient == NULL, VERR_INTERNAL_ERROR_2); 750 AssertReturn(pDevCfg->pIAudioRenderClient == NULL, VERR_INTERNAL_ERROR_2); 751 AssertReturn(PDMAudioPropsAreValid(&pDevCfg->Props), VERR_INTERNAL_ERROR_2); 752 753 PDRVHOSTAUDIOWASCACHEDEV pDevEntry = pDevCfg->pDevEntry; 754 AssertPtrReturn(pDevEntry, VERR_INTERNAL_ERROR_2); 755 AssertPtrReturn(pDevEntry->pIDevice, VERR_INTERNAL_ERROR_2); 756 AssertReturn(pDevEntry->enmDir == PDMAUDIODIR_IN || pDevEntry->enmDir == PDMAUDIODIR_OUT, VERR_INTERNAL_ERROR_2); 757 758 /* 759 * First we need an IAudioClient interface for calling IsFormatSupported 830 760 * on so we can get guidance as to what to do next. 831 761 * … … 835 765 * https://social.msdn.microsoft.com/Forums/en-US/1d974d90-6636-4121-bba3-a8861d9ab92a 836 766 * it is supported, just maybe missing from the SDK or something... 837 */ 838 RTCritSectLeave(&pThis->CritSectCache); 839 840 REFERENCE_TIME const cBufferSizeInNtTicks = PDMAudioPropsFramesToNtTicks(&pCfgReq->Props, pCfgReq->Backend.cFramesBufferSize); 841 767 * 768 * I'll leave the IsFormatSupported call here as it gives us a clue as to 769 * what exactly the WAS needs to convert our audio stream into/from. 770 */ 842 771 Log8Func(("Activating an IAudioClient for '%ls' ...\n", pDevEntry->wszDevId)); 843 772 IAudioClient *pIAudioClient = NULL; … … 848 777 { 849 778 LogRelMax(64, ("WasAPI: Activate(%ls, IAudioClient) failed: %Rhrc\n", pDevEntry->wszDevId, hrc)); 850 return NULL; 779 pDevCfg->nsInited = RTTimeNanoTS(); 780 return pDevCfg->rcSetup = VERR_AUDIO_STREAM_COULD_NOT_CREATE; 851 781 } 852 782 853 783 WAVEFORMATEX WaveFmtEx; 854 drvHostAudioWasWaveFmtExFrom Cfg(pCfgReq, &WaveFmtEx);784 drvHostAudioWasWaveFmtExFromProps(&pDevCfg->Props, &WaveFmtEx); 855 785 856 786 PWAVEFORMATEX pClosestMatch = NULL; … … 858 788 859 789 /* 860 * If the format is supported, create a cache entry for it.790 * If the format is supported, go ahead and initialize the client instance. 861 791 */ 862 792 if (SUCCEEDED(hrc)) 863 793 { 864 794 if (hrc == S_OK) 865 Log8Func(("IsFormatSupport(,%s,) -> S_OK + %p: requested format is supported\n", szProps, pClosestMatch));795 Log8Func(("IsFormatSupport(,%s,) -> S_OK + %p: requested format is supported\n", pDevCfg->szProps, pClosestMatch)); 866 796 else 867 Log8Func(("IsFormatSupport(,%s,) -> %Rhrc + %p: %uch S%u %uHz\n", szProps, hrc, pClosestMatch,797 Log8Func(("IsFormatSupport(,%s,) -> %Rhrc + %p: %uch S%u %uHz\n", pDevCfg->szProps, hrc, pClosestMatch, 868 798 pClosestMatch ? pClosestMatch->nChannels : 0, pClosestMatch ? pClosestMatch->wBitsPerSample : 0, 869 799 pClosestMatch ? pClosestMatch->nSamplesPerSec : 0)); 870 800 871 uint32_t fInitFlags = AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM 872 | AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY; 801 REFERENCE_TIME const cBufferSizeInNtTicks = PDMAudioPropsFramesToNtTicks(&pDevCfg->Props, pDevCfg->cFramesBufferSize); 802 uint32_t fInitFlags = AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM 803 | AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY; 873 804 hrc = pIAudioClient->Initialize(AUDCLNT_SHAREMODE_SHARED, fInitFlags, cBufferSizeInNtTicks, 874 805 0 /*cPeriodicityInNtTicks*/, &WaveFmtEx, NULL /*pAudioSessionGuid*/); 875 Log8Func(("Initialize(,%x, %RI64, %s,) -> %Rhrc\n", fInitFlags, cBufferSizeInNtTicks, szProps, hrc));806 Log8Func(("Initialize(,%x, %RI64, %s,) -> %Rhrc\n", fInitFlags, cBufferSizeInNtTicks, pDevCfg->szProps, hrc)); 876 807 if (SUCCEEDED(hrc)) 877 808 { 878 if (pClosestMatch) 879 CoTaskMemFree(pClosestMatch); 880 Log8Func(("Creating new config for '%s' on '%ls': %p\n", szProps, pDevEntry->wszDevId, pDevCfg)); 881 return drvHostAudioWasCacheCreateConfig(pDevEntry, pCfgReq, &WaveFmtEx, pIAudioClient); 882 } 883 884 LogRelMax(64, ("WasAPI: IAudioClient::Initialize(%s: %s) failed: %Rhrc\n", pCfgReq->szName, szProps, hrc)); 885 886 #if 0 /* later if needed */ 887 /* 888 * Try lookup or instantiate the closest config. 889 */ 890 PDMAUDIOSTREAMCFG ClosestCfg = *pCfgReq; 891 int rc = drvHostAudioWasCacheWaveFmtExToProps(&ClosestCfg.Props, pClosestMatch, pDevEntry->wszDevId); 892 if (RT_SUCCESS(rc)) 893 { 894 RTCritSectEnter(&pThis->CritSectCache); 895 pDevCfg = drvHostAudioWasCacheLookupLocked(pDevEntry, &pCfgReq->Props); 896 if (pDevCfg) 809 /* 810 * The direction specific client interface. 811 */ 812 if (pDevEntry->enmDir == PDMAUDIODIR_IN) 813 hrc = pIAudioClient->GetService(__uuidof(IAudioCaptureClient), (void **)&pDevCfg->pIAudioCaptureClient); 814 else 815 hrc = pIAudioClient->GetService(__uuidof(IAudioRenderClient), (void **)&pDevCfg->pIAudioRenderClient); 816 Log8Func(("GetService -> %Rhrc + %p\n", hrc, pDevEntry->enmDir == PDMAUDIODIR_IN 817 ? (void *)pDevCfg->pIAudioCaptureClient : (void *)pDevCfg->pIAudioRenderClient)); 818 if (SUCCEEDED(hrc)) 897 819 { 898 CoTaskMemFree(pClosestMatch); 899 Log8Func(("Config cache hit '%s' (for '%s') on '%ls': %p\n", pDevCfg->szProps, szProps, pDevEntry->wszDevId, pDevCfg)); 900 return pDevCfg; 820 /* 821 * Obtain the actual stream format and buffer config. 822 */ 823 UINT32 cFramesBufferSize = 0; 824 REFERENCE_TIME cDefaultPeriodInNtTicks = 0; 825 REFERENCE_TIME cMinimumPeriodInNtTicks = 0; 826 REFERENCE_TIME cLatencyinNtTicks = 0; 827 hrc = pIAudioClient->GetBufferSize(&cFramesBufferSize); 828 if (SUCCEEDED(hrc)) 829 { 830 hrc = pIAudioClient->GetDevicePeriod(&cDefaultPeriodInNtTicks, &cMinimumPeriodInNtTicks); 831 if (SUCCEEDED(hrc)) 832 { 833 hrc = pIAudioClient->GetStreamLatency(&cLatencyinNtTicks); 834 if (SUCCEEDED(hrc)) 835 { 836 LogRel2(("WasAPI: Aquired buffer parameters for %s:\n" 837 "WasAPI: cFramesBufferSize = %RU32\n" 838 "WasAPI: cDefaultPeriodInNtTicks = %RI64\n" 839 "WasAPI: cMinimumPeriodInNtTicks = %RI64\n" 840 "WasAPI: cLatencyinNtTicks = %RI64\n", 841 pDevCfg->szProps, cFramesBufferSize, cDefaultPeriodInNtTicks, 842 cMinimumPeriodInNtTicks, cLatencyinNtTicks)); 843 844 pDevCfg->pIAudioClient = pIAudioClient; 845 pDevCfg->cFramesBufferSize = cFramesBufferSize; 846 pDevCfg->cFramesPeriod = PDMAudioPropsNanoToFrames(&pDevCfg->Props, 847 cDefaultPeriodInNtTicks * 100); 848 pDevCfg->nsInited = RTTimeNanoTS(); 849 pDevCfg->rcSetup = VINF_SUCCESS; 850 851 if (pClosestMatch) 852 CoTaskMemFree(pClosestMatch); 853 Log8Func(("returns VINF_SUCCESS (%p (%s) inited in %'RU64 ns)\n", 854 pDevCfg, pDevCfg->szProps, pDevCfg->nsInited - pDevCfg->nsCreated)); 855 return VINF_SUCCESS; 856 } 857 LogRelMax(64, ("WasAPI: GetStreamLatency failed: %Rhrc\n", hrc)); 858 } 859 else 860 LogRelMax(64, ("WasAPI: GetDevicePeriod failed: %Rhrc\n", hrc)); 861 } 862 else 863 LogRelMax(64, ("WasAPI: GetBufferSize failed: %Rhrc\n", hrc)); 864 865 if (pDevCfg->pIAudioCaptureClient) 866 { 867 pDevCfg->pIAudioCaptureClient->Release(); 868 pDevCfg->pIAudioCaptureClient = NULL; 869 } 870 871 if (pDevCfg->pIAudioRenderClient) 872 { 873 pDevCfg->pIAudioRenderClient->Release(); 874 pDevCfg->pIAudioRenderClient = NULL; 875 } 901 876 } 902 RTCritSectLeave(&pThis->CritSectCache); 903 } 904 #endif 877 else 878 LogRelMax(64, ("WasAPI: IAudioClient::GetService(%s) failed: %Rhrc\n", pDevCfg->szProps, hrc)); 879 } 880 else 881 LogRelMax(64, ("WasAPI: IAudioClient::Initialize(%s) failed: %Rhrc\n", pDevCfg->szProps, hrc)); 905 882 } 906 883 else 907 LogRelMax(64,("WasAPI: IAudioClient::IsFormatSupport(,%s : %s,) failed: %Rhrc\n", pCfgReq->szName,szProps, hrc));884 LogRelMax(64,("WasAPI: IAudioClient::IsFormatSupport(,%s,) failed: %Rhrc\n", pDevCfg->szProps, hrc)); 908 885 909 886 pIAudioClient->Release(); 910 887 if (pClosestMatch) 911 888 CoTaskMemFree(pClosestMatch); 912 Log8Func(("returns NULL\n")); 913 return NULL; 889 pDevCfg->nsInited = RTTimeNanoTS(); 890 Log8Func(("returns VERR_AUDIO_STREAM_COULD_NOT_CREATE (inited in %'RU64 ns)\n", pDevCfg->nsInited - pDevCfg->nsCreated)); 891 return pDevCfg->rcSetup = VERR_AUDIO_STREAM_COULD_NOT_CREATE; 892 } 893 894 895 /** 896 * Worker for drvHostAudioWasCacheLookupOrCreate. 897 * 898 * If lookup fails, a new entry will be created. 899 * 900 * @note Called holding the lock, returning without holding it! 901 */ 902 static int drvHostAudioWasCacheLookupOrCreateConfig(PDRVHOSTAUDIOWAS pThis, PDRVHOSTAUDIOWASCACHEDEV pDevEntry, 903 PCPDMAUDIOSTREAMCFG pCfgReq, bool fOnWorker, 904 PDRVHOSTAUDIOWASCACHEDEVCFG *ppDevCfg) 905 { 906 /* 907 * Check if we've got a matching config. 908 */ 909 PDRVHOSTAUDIOWASCACHEDEVCFG pDevCfg = drvHostAudioWasCacheLookupLocked(pDevEntry, &pCfgReq->Props); 910 if (pDevCfg) 911 { 912 *ppDevCfg = pDevCfg; 913 RTCritSectLeave(&pThis->CritSectCache); 914 Log8Func(("Config cache hit '%s' on '%ls': %p\n", pDevCfg->szProps, pDevEntry->wszDevId, pDevCfg)); 915 return VINF_SUCCESS; 916 } 917 918 RTCritSectLeave(&pThis->CritSectCache); 919 920 /* 921 * Allocate an device config entry and hand the creation task over to the 922 * worker thread, unless we're already on it. 923 */ 924 pDevCfg = (PDRVHOSTAUDIOWASCACHEDEVCFG)RTMemAllocZ(sizeof(*pDevCfg)); 925 AssertReturn(pDevCfg, VERR_NO_MEMORY); 926 RTListInit(&pDevCfg->ListEntry); 927 pDevCfg->pDevEntry = pDevEntry; 928 pDevCfg->rcSetup = VERR_AUDIO_STREAM_INIT_IN_PROGRESS; 929 pDevCfg->Props = pCfgReq->Props; 930 pDevCfg->cFramesBufferSize = pCfgReq->Backend.cFramesBufferSize; 931 PDMAudioPropsToString(&pDevCfg->Props, pDevCfg->szProps, sizeof(pDevCfg->szProps)); 932 pDevCfg->nsCreated = RTTimeNanoTS(); 933 934 if (!fOnWorker) 935 { 936 *ppDevCfg = pDevCfg; 937 LogFlowFunc(("Doing the rest of the work on %p via pfnStreamInitAsync...\n", pDevCfg)); 938 return VINF_AUDIO_STREAM_ASYNC_INIT_NEEDED; 939 } 940 941 /* 942 * Initialize the entry on the calling thread. 943 */ 944 int rc = drvHostAudioWasCacheInitConfig(pDevCfg); 945 AssertRC(pDevCfg->rcSetup == rc); 946 if (RT_SUCCESS(rc)) 947 rc = pDevCfg->rcSetup; /* paranoia */ 948 if (RT_SUCCESS(rc)) 949 { 950 *ppDevCfg = pDevCfg; 951 LogFlowFunc(("Returning %p\n", pDevCfg)); 952 return VINF_SUCCESS; 953 } 954 RTMemFree(pDevCfg); 955 *ppDevCfg = NULL; 956 return rc; 914 957 } 915 958 … … 919 962 * if missing. 920 963 * 921 * @returns Pointer to the requested device config (or closest alternative). 922 * NULL on failure (TODO: need to return why). 964 * @returns VBox status code. 923 965 * @param pThis The WASAPI host audio driver instance data. 924 966 * @param pIDevice The device to look up. 925 967 * @param pCfgReq The configuration to look up. 926 */ 927 static PDRVHOSTAUDIOWASCACHEDEVCFG 928 drvHostAudioWasCacheLookupOrCreate(PDRVHOSTAUDIOWAS pThis, IMMDevice *pIDevice, PCPDMAUDIOSTREAMCFG pCfgReq) 929 { 968 * @param fOnWorker Set if we're on a worker thread, otherwise false. 969 * @param ppDevCfg Where to return the requested device config. 970 */ 971 static int drvHostAudioWasCacheLookupOrCreate(PDRVHOSTAUDIOWAS pThis, IMMDevice *pIDevice, PCPDMAUDIOSTREAMCFG pCfgReq, 972 bool fOnWorker, PDRVHOSTAUDIOWASCACHEDEVCFG *ppDevCfg) 973 { 974 *ppDevCfg = NULL; 975 930 976 /* 931 977 * Get the device ID so we can perform the lookup. 932 978 */ 979 int rc = VERR_AUDIO_STREAM_COULD_NOT_CREATE; 933 980 LPWSTR pwszDevId = NULL; 934 981 HRESULT hrc = pIDevice->GetId(&pwszDevId); … … 950 997 CoTaskMemFree(pwszDevId); 951 998 Log8Func(("Cache hit for device '%ls': %p\n", pDevEntry->wszDevId, pDevEntry)); 952 return drvHostAudioWasCacheLookupOrCreateConfig(pThis, pDevEntry, pCfgReq );999 return drvHostAudioWasCacheLookupOrCreateConfig(pThis, pDevEntry, pCfgReq, fOnWorker, ppDevCfg); 953 1000 } 954 1001 } … … 992 1039 993 1040 Log8Func(("Lost race adding device '%ls': %p\n", pDevEntry2->wszDevId, pDevEntry2)); 994 return drvHostAudioWasCacheLookupOrCreateConfig(pThis, pDevEntry2, pCfgReq );1041 return drvHostAudioWasCacheLookupOrCreateConfig(pThis, pDevEntry2, pCfgReq, fOnWorker, ppDevCfg); 995 1042 } 996 1043 } … … 998 1045 999 1046 Log8Func(("Added device '%ls' to cache: %p\n", pDevEntry->wszDevId, pDevEntry)); 1000 return drvHostAudioWasCacheLookupOrCreateConfig(pThis, pDevEntry, pCfgReq );1047 return drvHostAudioWasCacheLookupOrCreateConfig(pThis, pDevEntry, pCfgReq, fOnWorker, ppDevCfg); 1001 1048 } 1002 1049 CoTaskMemFree(pwszDevId); … … 1004 1051 else 1005 1052 LogRelMax(64, ("WasAPI: GetId failed (lookup): %Rhrc\n", hrc)); 1006 return NULL;1053 return rc; 1007 1054 } 1008 1055 … … 1019 1066 * Reset the audio client to see that it works and to make sure it's in a sensible state. 1020 1067 */ 1021 HRESULT hrc = pDevCfg->pIAudioClient->Reset(); 1068 HRESULT hrc = pDevCfg->pIAudioClient ? pDevCfg->pIAudioClient->Reset() 1069 : pDevCfg->rcSetup == VERR_AUDIO_STREAM_INIT_IN_PROGRESS ? S_OK : E_FAIL; 1022 1070 if (SUCCEEDED(hrc)) 1023 1071 { … … 1035 1083 1036 1084 1037 static void drvHostWasCacheConfigHinting(PDRVHOSTAUDIOWAS pThis, PPDMAUDIOSTREAMCFG pCfgReq )1085 static void drvHostWasCacheConfigHinting(PDRVHOSTAUDIOWAS pThis, PPDMAUDIOSTREAMCFG pCfgReq, bool fOnWorker) 1038 1086 { 1039 1087 /* … … 1050 1098 * Look up the config and put it back. 1051 1099 */ 1052 PDRVHOSTAUDIOWASCACHEDEVCFG pDevCfg = drvHostAudioWasCacheLookupOrCreate(pThis, pIDevice, pCfgReq); 1053 LogFlowFunc(("pDevCfg=%p\n")); 1054 if (pDevCfg) 1100 PDRVHOSTAUDIOWASCACHEDEVCFG pDevCfg = NULL; 1101 int rc = drvHostAudioWasCacheLookupOrCreate(pThis, pIDevice, pCfgReq, fOnWorker, &pDevCfg); 1102 LogFlowFunc(("pDevCfg=%p rc=%Rrc\n", pDevCfg, rc)); 1103 if (pDevCfg && RT_SUCCESS(rc)) 1055 1104 drvHostAudioWasCachePutBack(pThis, pDevCfg); 1056 1105 pIDevice->Release(); … … 1114 1163 * Worker thread * 1115 1164 *********************************************************************************************************************************/ 1165 #if 0 1116 1166 1117 1167 /** … … 1148 1198 switch (Msg.message) 1149 1199 { 1150 case WM_DRVHOSTAUDIOWAS_HINT:1151 {1152 AssertMsgBreak(Msg.wParam == pThis->uWorkerThreadFixedParam, ("%p\n", Msg.wParam));1153 AssertBreak(Msg.hwnd == NULL);1154 PPDMAUDIOSTREAMCFG pCfgReq = (PPDMAUDIOSTREAMCFG)Msg.lParam;1155 AssertPtrBreak(pCfgReq);1156 1157 drvHostWasCacheConfigHinting(pThis, pCfgReq);1158 RTMemFree(pCfgReq);1159 break;1160 }1161 1162 1200 case WM_DRVHOSTAUDIOWAS_PURGE_CACHE: 1163 1201 { … … 1185 1223 return VINF_SUCCESS; 1186 1224 } 1187 1225 #endif 1188 1226 1189 1227 /********************************************************************************************************************************* … … 1206 1244 RTStrCopy(pBackendCfg->szName, sizeof(pBackendCfg->szName), "WasAPI"); 1207 1245 pBackendCfg->cbStream = sizeof(DRVHOSTAUDIOWASSTREAM); 1208 pBackendCfg->fFlags = 0;1246 pBackendCfg->fFlags = PDMAUDIOBACKEND_F_ASYNC_HINT; 1209 1247 pBackendCfg->cMaxStreamsIn = UINT32_MAX; 1210 1248 pBackendCfg->cMaxStreamsOut = UINT32_MAX; … … 1401 1439 1402 1440 /** 1441 * @interface_method_impl{PDMIHOSTAUDIO,pfnDoOnWorkerThread} 1442 */ 1443 static DECLCALLBACK(void) drvHostAudioWasHA_DoOnWorkerThread(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream, 1444 uintptr_t uUser, void *pvUser) 1445 { 1446 PDRVHOSTAUDIOWAS pThis = RT_FROM_MEMBER(pInterface, DRVHOSTAUDIOWAS, IHostAudio); 1447 RT_NOREF(pStream, pvUser); 1448 LogFlowFunc(("uUser=%#zx pStream=%p pvUser=%p\n", uUser, pStream, pvUser)); 1449 1450 switch (uUser) 1451 { 1452 case DRVHOSTAUDIOWAS_DO_PURGE_CACHE: 1453 Assert(pStream == NULL); 1454 Assert(pvUser == NULL); 1455 drvHostAudioWasCachePurge(pThis); 1456 break; 1457 1458 default: 1459 AssertMsgFailedBreak(("%#zx\n", uUser)); 1460 } 1461 } 1462 1463 1464 /** 1403 1465 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamConfigHint} 1466 * 1467 * @note This is called on a DrvAudio worker thread. 1404 1468 */ 1405 1469 static DECLCALLBACK(void) drvHostAudioWasHA_StreamConfigHint(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAMCFG pCfg) 1406 1470 { 1471 #if 0 /* disable to test async stream creation. */ 1407 1472 PDRVHOSTAUDIOWAS pThis = RT_FROM_MEMBER(pInterface, DRVHOSTAUDIOWAS, IHostAudio); 1408 1473 LogFlowFunc(("pCfg=%p\n", pCfg)); 1409 1474 1410 if (pThis->hWorkerThread != NIL_RTTHREAD) 1411 { 1412 PPDMAUDIOSTREAMCFG pCfgCopy = PDMAudioStrmCfgDup(pCfg); 1413 if (pCfgCopy) 1414 { 1415 if (PostThreadMessageW(pThis->idWorkerThread, WM_DRVHOSTAUDIOWAS_HINT, 1416 pThis->uWorkerThreadFixedParam, (LPARAM)pCfgCopy)) 1417 LogFlowFunc(("Posted %p to worker thread\n", pCfgCopy)); 1418 else 1419 { 1420 LogRelMax(64, ("WasAPI: PostThreadMessageW failed: %u\n", GetLastError())); 1421 PDMAudioStrmCfgFree(pCfgCopy); 1422 } 1423 } 1424 } 1425 else 1426 drvHostWasCacheConfigHinting(pThis, pCfg); 1475 drvHostWasCacheConfigHinting(pThis, pCfg); 1476 #else 1477 RT_NOREF(pInterface, pCfg); 1478 #endif 1427 1479 } 1428 1480 … … 1458 1510 */ 1459 1511 WAVEFORMATEX WaveFmtX; 1460 drvHostAudioWasWaveFmtExFrom Cfg(pCfgReq, &WaveFmtX);1512 drvHostAudioWasWaveFmtExFromProps(&pCfgReq->Props, &WaveFmtX); 1461 1513 LogRel2(("WasAPI: Requested %s format for '%s':\n" 1462 1514 "WasAPI: wFormatTag = %RU16\n" … … 1506 1558 /** @todo make it return a status code too and retry if the default device 1507 1559 * was invalidated/changed while we where working on it here. */ 1508 int rc = VERR_AUDIO_STREAM_COULD_NOT_CREATE;1509 PDRVHOSTAUDIOWASCACHEDEVCFG pDevCfg = drvHostAudioWasCacheLookupOrCreate(pThis, pIDevice, pCfgReq);1560 PDRVHOSTAUDIOWASCACHEDEVCFG pDevCfg = NULL; 1561 int rc = drvHostAudioWasCacheLookupOrCreate(pThis, pIDevice, pCfgReq, false /*fOnWorker*/, &pDevCfg); 1510 1562 1511 1563 pIDevice->Release(); 1512 1564 pIDevice = NULL; 1513 1565 1514 if (pDevCfg )1566 if (pDevCfg && RT_SUCCESS(rc)) 1515 1567 { 1516 1568 pStreamWas->pDevCfg = pDevCfg; 1517 1569 1518 pCfgAcq->Props = pDevCfg->Props;1570 pCfgAcq->Props = pDevCfg->Props; 1519 1571 pCfgAcq->Backend.cFramesBufferSize = pDevCfg->cFramesBufferSize; 1520 1572 pCfgAcq->Backend.cFramesPeriod = pDevCfg->cFramesPeriod; … … 1532 1584 RTCritSectRwLeaveExcl(&pThis->CritSectStreamList); 1533 1585 1534 LogFlowFunc(("returns VINF_SUCCESS\n", rc)); 1535 return VINF_SUCCESS; 1586 if (pStreamWas->pDevCfg->pIAudioClient != NULL) 1587 { 1588 LogFlowFunc(("returns VINF_SUCCESS\n", rc)); 1589 return VINF_SUCCESS; 1590 } 1591 LogFlowFunc(("returns VINF_AUDIO_STREAM_ASYNC_INIT_NEEDED\n", rc)); 1592 return VINF_AUDIO_STREAM_ASYNC_INIT_NEEDED; 1536 1593 } 1537 1594 … … 1541 1598 } 1542 1599 else 1543 LogRelMax(64, ("WasAPI: Failed to setup %s on audio device '%ls' .\n", pszStreamType, pwszDevIdDesc));1600 LogRelMax(64, ("WasAPI: Failed to setup %s on audio device '%ls' (%Rrc).\n", pszStreamType, pwszDevIdDesc, rc)); 1544 1601 1545 1602 LogFlowFunc(("returns %Rrc\n", rc)); 1603 return rc; 1604 } 1605 1606 1607 /** 1608 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamInitAsync} 1609 */ 1610 static DECLCALLBACK(int) drvHostAudioWasHA_StreamInitAsync(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream, 1611 bool fDestroyed) 1612 { 1613 RT_NOREF(pInterface); 1614 PDRVHOSTAUDIOWASSTREAM pStreamWas = (PDRVHOSTAUDIOWASSTREAM)pStream; 1615 AssertPtrReturn(pStreamWas, VERR_INVALID_POINTER); 1616 LogFlowFunc(("Stream '%s'%s\n", pStreamWas->Cfg.szName, fDestroyed ? " - destroyed!" : "")); 1617 1618 /* 1619 * Assert sane preconditions for this call. 1620 */ 1621 AssertPtrReturn(pStreamWas->Core.pStream, VERR_INTERNAL_ERROR); 1622 AssertPtrReturn(pStreamWas->pDevCfg, VERR_INTERNAL_ERROR_2); 1623 AssertPtrReturn(pStreamWas->pDevCfg->pDevEntry, VERR_INTERNAL_ERROR_3); 1624 AssertPtrReturn(pStreamWas->pDevCfg->pDevEntry->pIDevice, VERR_INTERNAL_ERROR_4); 1625 AssertReturn(pStreamWas->pDevCfg->pDevEntry->enmDir == pStreamWas->Core.pStream->enmDir, VERR_INTERNAL_ERROR_4); 1626 AssertReturn(pStreamWas->pDevCfg->pIAudioClient == NULL, VERR_INTERNAL_ERROR_5); 1627 AssertReturn(pStreamWas->pDevCfg->pIAudioRenderClient == NULL, VERR_INTERNAL_ERROR_5); 1628 AssertReturn(pStreamWas->pDevCfg->pIAudioCaptureClient == NULL, VERR_INTERNAL_ERROR_5); 1629 1630 /* 1631 * Do the job. 1632 */ 1633 int rc; 1634 if (!fDestroyed) 1635 rc = drvHostAudioWasCacheInitConfig(pStreamWas->pDevCfg); 1636 else 1637 { 1638 AssertReturn(pStreamWas->pDevCfg->rcSetup == VERR_AUDIO_STREAM_INIT_IN_PROGRESS, VERR_INTERNAL_ERROR_2); 1639 pStreamWas->pDevCfg->rcSetup = VERR_WRONG_ORDER; 1640 rc = VINF_SUCCESS; 1641 } 1642 1643 LogFlowFunc(("returns %Rrc (%s)\n", rc, pStreamWas->Cfg.szName)); 1546 1644 return rc; 1547 1645 } … … 2086 2184 AssertPtrReturn(pStreamWas, PDMAUDIOSTREAM_STS_NONE); 2087 2185 2088 uint32_t fStrmStatus = PDMAUDIOSTREAM_STS_INITIALIZED; 2186 uint32_t fStrmStatus = 0; 2187 AssertPtr(pStreamWas->pDevCfg); 2188 if (pStreamWas->pDevCfg /*paranoia*/) 2189 { 2190 if (RT_SUCCESS(pStreamWas->pDevCfg->rcSetup)) 2191 fStrmStatus |= PDMAUDIOSTREAM_STS_INITIALIZED; 2192 else if (pStreamWas->pDevCfg->rcSetup != VERR_AUDIO_STREAM_INIT_IN_PROGRESS) 2193 { 2194 /** @todo trigger device reset? Probably won't help, so what to do? */ 2195 } 2196 } 2089 2197 if (pStreamWas->fEnabled) 2090 2198 fStrmStatus |= PDMAUDIOSTREAM_STS_ENABLED; … … 2418 2526 PDRVHOSTAUDIOWAS pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTAUDIOWAS); 2419 2527 2528 /* 2529 * Start purging the cache asynchronously before we get to destruct. 2530 * This might speed up VM shutdown a tiny fraction and also stress 2531 * the shutting down of the thread pool a little. 2532 */ 2533 #if 0 2420 2534 if (pThis->hWorkerThread != NIL_RTTHREAD) 2421 2535 { … … 2424 2538 Assert(fRc); RT_NOREF(fRc); 2425 2539 } 2540 #else 2541 if (!RTListIsEmpty(&pThis->CacheHead) && pThis->pIHostAudioPort) 2542 { 2543 int rc = pThis->pIHostAudioPort->pfnDoOnWorkerThread(pThis->pIHostAudioPort, NULL/*pStream*/, 2544 DRVHOSTAUDIOWAS_DO_PURGE_CACHE, NULL /*pvUser*/); 2545 AssertRC(rc); 2546 } 2547 #endif 2426 2548 } 2427 2549 … … 2443 2565 } 2444 2566 2567 #if 0 2445 2568 if (pThis->hWorkerThread != NIL_RTTHREAD) 2446 2569 { … … 2451 2574 AssertRC(rc); 2452 2575 } 2576 #endif 2453 2577 2454 2578 if (RTCritSectIsInitialized(&pThis->CritSectCache)) … … 2498 2622 pThis->pDrvIns = pDrvIns; 2499 2623 pThis->hDrainTimer = NIL_TMTIMERHANDLE; 2624 #if 0 2500 2625 pThis->hWorkerThread = NIL_RTTHREAD; 2501 2626 pThis->idWorkerThread = 0; 2627 #endif 2502 2628 RTListInit(&pThis->StreamHead); 2503 2629 RTListInit(&pThis->CacheHead); … … 2508 2634 pThis->IHostAudio.pfnGetDevices = drvHostAudioWasHA_GetDevices; 2509 2635 pThis->IHostAudio.pfnGetStatus = drvHostAudioWasHA_GetStatus; 2636 pThis->IHostAudio.pfnDoOnWorkerThread = drvHostAudioWasHA_DoOnWorkerThread; 2510 2637 pThis->IHostAudio.pfnStreamConfigHint = drvHostAudioWasHA_StreamConfigHint; 2511 2638 pThis->IHostAudio.pfnStreamCreate = drvHostAudioWasHA_StreamCreate; 2639 pThis->IHostAudio.pfnStreamInitAsync = drvHostAudioWasHA_StreamInitAsync; 2512 2640 pThis->IHostAudio.pfnStreamDestroy = drvHostAudioWasHA_StreamDestroy; 2513 2641 pThis->IHostAudio.pfnStreamNotifyDeviceChanged = NULL; … … 2560 2688 * Resolve the notification interface. 2561 2689 */ 2562 pThis->pI AudioNotifyFromHost = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIAUDIONOTIFYFROMHOST);2690 pThis->pIHostAudioPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIHOSTAUDIOPORT); 2563 2691 # ifdef VBOX_WITH_AUDIO_CALLBACKS 2564 AssertPtr(pThis->pI AudioNotifyFromHost);2692 AssertPtr(pThis->pIHostAudioPort); 2565 2693 # endif 2566 2694 … … 2645 2773 AssertRCReturn(rc, rc); 2646 2774 2775 #if 0 2647 2776 /* 2648 2777 * Create the worker thread. This thread has a message loop and will be … … 2657 2786 rc = RTThreadUserWait(pThis->hWorkerThread, RT_MS_10SEC); 2658 2787 AssertRC(rc); 2788 #endif 2659 2789 2660 2790 /* -
trunk/src/VBox/Main/src-client/DrvAudioRec.cpp
r88761 r88819 1102 1102 pThis->IHostAudio.pfnGetDevices = NULL; 1103 1103 pThis->IHostAudio.pfnGetStatus = drvAudioVideoRecHA_GetStatus; 1104 pThis->IHostAudio.pfnDoOnWorkerThread = NULL; 1105 pThis->IHostAudio.pfnStreamConfigHint = NULL; 1104 1106 pThis->IHostAudio.pfnStreamCreate = drvAudioVideoRecHA_StreamCreate; 1107 pThis->IHostAudio.pfnStreamInitAsync = NULL; 1105 1108 pThis->IHostAudio.pfnStreamDestroy = drvAudioVideoRecHA_StreamDestroy; 1106 1109 pThis->IHostAudio.pfnStreamNotifyDeviceChanged = NULL; -
trunk/src/VBox/Main/src-client/DrvAudioVRDE.cpp
r88761 r88819 725 725 pThis->IHostAudio.pfnGetDevices = NULL; 726 726 pThis->IHostAudio.pfnGetStatus = drvAudioVrdeHA_GetStatus; 727 pThis->IHostAudio.pfnDoOnWorkerThread = NULL; 728 pThis->IHostAudio.pfnStreamConfigHint = NULL; 727 729 pThis->IHostAudio.pfnStreamCreate = drvAudioVrdeHA_StreamCreate; 730 pThis->IHostAudio.pfnStreamInitAsync = NULL; 728 731 pThis->IHostAudio.pfnStreamDestroy = drvAudioVrdeHA_StreamDestroy; 729 732 pThis->IHostAudio.pfnStreamNotifyDeviceChanged = NULL;
Note:
See TracChangeset
for help on using the changeset viewer.