Changeset 87567 in vbox for trunk/src/VBox/Devices
- Timestamp:
- Feb 3, 2021 2:25:29 PM (4 years ago)
- svn:sync-xref-src-repo-rev:
- 142594
- Location:
- trunk/src/VBox/Devices/Audio
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Audio/DevHDA.cpp
r87464 r87567 1343 1343 1344 1344 uint64_t const tsNow = PDMDevHlpTimerGet(pDevIns, pStreamShared->hTimer); 1345 rc2 = hdaR3TimerSet(pDevIns, pStreamShared, tsNow + pStreamShared->State.cTransferTicks, false /* fForce */, tsNow);1345 rc2 = hdaR3TimerSet(pDevIns, pStreamShared, tsNow + pStreamShared->State.cTransferTicks, true /* fForce */, tsNow); 1346 1346 AssertRC(rc2); 1347 1347 } … … 1448 1448 Assert(tsNow >= pStreamShared->State.tsTransferLast); 1449 1449 1450 const uint64_t cTicksElapsed = tsNow - pStreamShared->State.tsTransferLast; 1451 # ifdef LOG_ENABLED 1452 const uint64_t cTicksTransferred = pStreamShared->State.cbTransferProcessed * pStreamShared->State.cTicksPerByte; 1453 # endif 1454 1455 Log3Func(("[SD%RU8] cTicksElapsed=%RU64, cTicksTransferred=%RU64, cTicksToNext=%RU64\n", 1456 uSD, cTicksElapsed, cTicksTransferred, cTicksToNext)); 1457 1458 Log3Func(("[SD%RU8] cbTransferProcessed=%RU32, cbTransferChunk=%RU32, cbTransferSize=%RU32\n", uSD, 1459 pStreamShared->State.cbTransferProcessed, pStreamShared->State.cbTransferChunk, pStreamShared->State.cbTransferSize)); 1450 const uint64_t cTicksElapsed = tsNow - pStreamShared->State.tsTransferLast; 1451 1452 Log3Func(("[SD%RU8] cTicksElapsed=%RU64, cTicksToNext=%RU64\n", 1453 uSD, cTicksElapsed, cTicksToNext)); 1460 1454 1461 1455 if (cTicksElapsed <= cTicksToNext) … … 1469 1463 uSD, cTicksToNext / 1000, cTicksElapsed / 1000, pStreamShared->State.cTransferPendingInterrupts)); 1470 1464 1471 cTicksToNext = 0;1465 cTicksToNext = pStreamShared->State.cbTransferSize * pStreamShared->State.cTicksPerByte; 1472 1466 } 1473 1467 … … 1475 1469 1476 1470 /* Reset processed data counter. */ 1477 pStreamShared->State.cbTransferProcessed = 0; 1478 pStreamShared->State.tsTransferNext = tsNow + cTicksToNext; 1471 pStreamShared->State.tsTransferNext = tsNow + cTicksToNext; 1479 1472 1480 1473 /* Only re-arm the timer if there were pending transfer interrupts left … … 1486 1479 1487 1480 /* Re-arm the timer. */ 1488 LogFunc((" Timer set SD%RU8\n", uSD));1481 LogFunc(("[SD%RU8] Timer set\n", uSD)); 1489 1482 hdaR3TimerSet(pDevIns, pStreamShared, tsNow + cTicksToNext, 1490 1483 true /* fForce - we just set tsTransferNext*/, 0 /*tsNow*/); … … 3918 3911 { 3919 3912 /* Paranoia. */ 3920 AssertLogRelMsgReturn(cbCircBufSize <= _ 1M,3913 AssertLogRelMsgReturn(cbCircBufSize <= _32M, 3921 3914 ("HDA: Saved state contains bogus DMA buffer size (%RU32) for stream #%RU8", 3922 3915 cbCircBufSize, idStream), … … 4599 4592 4600 4593 /* Note: Error checking of this value happens in hdaR3StreamSetUp(). */ 4601 int rc = pHlp->pfnCFGMQueryU16Def(pCfg, "BufSizeInMs", &pThis->cbCircBufInMs, RT_MS_1 SEC /* Default value, if not set. */);4594 int rc = pHlp->pfnCFGMQueryU16Def(pCfg, "BufSizeInMs", &pThis->cbCircBufInMs, RT_MS_10SEC /* Default value, if not set. */); 4602 4595 if (RT_FAILURE(rc)) 4603 4596 return PDMDEV_SET_ERROR(pDevIns, rc, … … 4605 4598 4606 4599 /* Note: Error checking of this value happens in hdaR3StreamSetUp(). */ 4607 rc = pHlp->pfnCFGMQueryU16Def(pCfg, "BufSizeOutMs", &pThis->cbCircBufOutMs, RT_MS_1 SEC /* Default value, if not set. */);4600 rc = pHlp->pfnCFGMQueryU16Def(pCfg, "BufSizeOutMs", &pThis->cbCircBufOutMs, RT_MS_10SEC /* Default value, if not set. */); 4608 4601 if (RT_FAILURE(rc)) 4609 4602 return PDMDEV_SET_ERROR(pDevIns, rc, -
trunk/src/VBox/Devices/Audio/DevHDA.h
r87436 r87567 33 33 #include "HDAStreamPeriod.h" 34 34 35 35 #ifdef DEBUG_andy 36 /** Enables strict mode, which checks for stuff which isn't supposed to happen. 37 * Be prepared for assertions coming in! */ 38 # define HDA_STRICT 39 #endif 36 40 37 41 /** -
trunk/src/VBox/Devices/Audio/HDAStream.cpp
r87465 r87567 30 30 #include <VBox/vmm/pdmaudioifs.h> 31 31 32 #include <math.h> /* Needed for round(). */ 33 32 34 #include "DrvAudio.h" 33 35 … … 41 43 * Internal Functions * 42 44 *********************************************************************************************************************************/ 43 static void hdaR3StreamSetPosition (PHDASTREAM pStreamShared, PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t u32LPIB);45 static void hdaR3StreamSetPositionAbs(PHDASTREAM pStreamShared, PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t uLPIB); 44 46 45 47 static int hdaR3StreamAsyncIODestroy(PHDASTREAMR3 pStreamR3); … … 82 84 rc = hdaR3StreamPeriodCreate(&pStreamShared->State.Period); 83 85 AssertRCReturn(rc, rc); 84 85 pStreamShared->State.tsLastUpdateNs = 0;86 86 87 87 #ifdef DEBUG … … 361 361 } 362 362 363 const uint32_t cbCircBufDefault = DrvAudioHlpMilliToBytes(RT_MS_1 SEC, &pCfg->Props);363 const uint32_t cbCircBufDefault = DrvAudioHlpMilliToBytes(RT_MS_10SEC, &pCfg->Props); 364 364 365 365 uint32_t cbCircBuf = DrvAudioHlpMilliToBytes( hdaGetDirFromSD(uSD) == PDMAUDIODIR_IN … … 506 506 */ 507 507 508 /* Calculate the fragment size the guest OS expects interrupt delivery at. */ 509 pStreamShared->State.cbTransferSize = pStreamShared->u32CBL / cFragments; 510 Assert(pStreamShared->State.cbTransferSize); 511 Assert(pStreamShared->State.cbTransferSize % pStreamR3->State.Mapping.cbFrameSize == 0); 508 /* Prevent division by zero. */ 509 ASSERT_GUEST_LOGREL_MSG_STMT(pStreamShared->State.uTimerHz, 510 ("Timer Hz rate for stream #%RU8 is invalid\n", uSD), 511 pStreamShared->State.uTimerHz = HDA_TIMER_HZ_DEFAULT); 512 /* 513 * Calculate the fragment size the guest OS expects interrupt delivery at. 514 * 515 * Guests also expect a very extact DMA timing for reading / writing audio data, so we run on a constant 516 * (virtual) rate which we expose to the guest. 517 * 518 * Data rate examples: 519 * * Windows 10 @ 44,1kHz / 16-bit stereo 520 * * Default mode: 448 audio frames (~10.15ms) = 1792 byte / ~10ms. 521 * * Fast mode: 128 audio frames (~ 2.90ms) = 512 byte / ~3ms. 522 */ 523 pStreamShared->State.cbTransferSize 524 = (pStreamShared->State.Cfg.Props.uHz * pStreamR3->State.Mapping.cbFrameSize) / pStreamShared->State.uTimerHz; 512 525 ASSERT_GUEST_LOGREL_MSG_STMT(pStreamShared->State.cbTransferSize, 513 526 ("Transfer size for stream #%RU8 is invalid\n", uSD), rc = VERR_INVALID_PARAMETER); 514 527 if (RT_SUCCESS(rc)) 515 528 { 516 /* Calculate the bytes we need to transfer to / from the stream's DMA per iteration. 517 * This is bound to the device's Hz rate and thus to the (virtual) timing the device expects. */ 518 pStreamShared->State.cbTransferChunk = (pStreamShared->State.Cfg.Props.uHz / pStreamShared->State.uTimerHz) * pStreamR3->State.Mapping.cbFrameSize; 519 Assert(pStreamShared->State.cbTransferChunk); 520 Assert(pStreamShared->State.cbTransferChunk % pStreamR3->State.Mapping.cbFrameSize == 0); 529 /* 530 * Calculate the bytes we need to transfer to / from the stream's DMA per iteration. 531 * This is bound to the device's Hz rate and thus to the (virtual) timing the device expects. 532 * 533 * As we don't do chunked transfers the moment, the chunk size equals the overall transfer size. 534 */ 535 pStreamShared->State.cbTransferChunk = pStreamShared->State.cbTransferSize; 521 536 ASSERT_GUEST_LOGREL_MSG_STMT(pStreamShared->State.cbTransferChunk, 522 537 ("Transfer chunk for stream #%RU8 is invalid\n", uSD), … … 525 540 { 526 541 /* Make sure that the transfer chunk does not exceed the overall transfer size. */ 527 if (pStreamShared->State.cbTransferChunk > pStreamShared->State.cbTransferSize) 528 pStreamShared->State.cbTransferChunk = pStreamShared->State.cbTransferSize; 529 530 const uint64_t cTicksPerHz = PDMDevHlpTimerGetFreq(pDevIns, pStreamShared->hTimer) / pStreamShared->State.uTimerHz; 542 AssertStmt(pStreamShared->State.cbTransferChunk <= pStreamShared->State.cbTransferSize, 543 pStreamShared->State.cbTransferChunk = pStreamShared->State.cbTransferSize); 544 545 const uint64_t uTimerFreq = PDMDevHlpTimerGetFreq(pDevIns, pStreamShared->hTimer); 546 547 const double cTicksPerHz = uTimerFreq / pStreamShared->State.uTimerHz; 548 const double cTicksPerByte = cTicksPerHz / (double)pStreamShared->State.cbTransferChunk; 531 549 532 550 /* Calculate the timer ticks per byte for this stream. */ 533 pStreamShared->State.cTicksPerByte = cTicksPerHz / pStreamShared->State.cbTransferChunk;551 pStreamShared->State.cTicksPerByte = round(cTicksPerByte); /** @todo r=andy Do we have rounding in IPRT? */ 534 552 Assert(pStreamShared->State.cTicksPerByte); 535 553 554 const double cTransferTicks = pStreamShared->State.cbTransferChunk * cTicksPerByte; 555 536 556 /* Calculate timer ticks per transfer. */ 537 pStreamShared->State.cTransferTicks = pStreamShared->State.cbTransferChunk * pStreamShared->State.cTicksPerByte;557 pStreamShared->State.cTransferTicks = round(cTransferTicks); 538 558 Assert(pStreamShared->State.cTransferTicks); 539 559 540 LogFunc(("[SD%RU8] Timer %uHz (%RU64 ticks per Hz), cTicksPerByte=%RU64, cbTransferChunk=%RU32, " \ 541 "cTransferTicks=%RU64, cbTransferSize=%RU32\n", 542 uSD, pStreamShared->State.uTimerHz, cTicksPerHz, pStreamShared->State.cTicksPerByte, 543 pStreamShared->State.cbTransferChunk, pStreamShared->State.cTransferTicks, pStreamShared->State.cbTransferSize)); 560 LogRel2(("HDA: Stream #%RU8 is using %uHz device timer (%RU64 virtual ticks / Hz), stream Hz=%RU32, " 561 "cTicksPerByte=%RU64, cTransferTicks=%RU64 -> cbTransferChunk=%RU32 (%RU64ms), cbTransferSize=%RU32 (%RU64ms)\n", 562 uSD, pStreamShared->State.uTimerHz, (uint64_t)cTicksPerHz, pStreamShared->State.Cfg.Props.uHz, 563 pStreamShared->State.cTicksPerByte, pStreamShared->State.cTransferTicks, 564 pStreamShared->State.cbTransferChunk, DrvAudioHlpBytesToMilli(pStreamShared->State.cbTransferChunk, &pCfg->Props), 565 pStreamShared->State.cbTransferSize, DrvAudioHlpBytesToMilli(pStreamShared->State.cbTransferSize, &pCfg->Props))); 544 566 545 567 /* Make sure to also update the stream's DMA counter (based on its current LPIB value). */ 546 hdaR3StreamSetPosition (pStreamShared, pDevIns, pThis, HDA_STREAM_REG(pThis, LPIB, uSD));568 hdaR3StreamSetPositionAbs(pStreamShared, pDevIns, pThis, HDA_STREAM_REG(pThis, LPIB, uSD)); 547 569 548 570 #ifdef LOG_ENABLED … … 613 635 614 636 /* Reset transfer stuff. */ 615 pStreamShared->State.cbTransferProcessed = 0;616 637 pStreamShared->State.cTransferPendingInterrupts = 0; 617 638 pStreamShared->State.tsTransferLast = 0; … … 715 736 } 716 737 738 #if 0 /* Not used atm. */ 717 739 static uint32_t hdaR3StreamGetPosition(PHDASTATE pThis, PHDASTREAM pStreamShared) 718 740 { 719 741 return HDA_STREAM_REG(pThis, LPIB, pStreamShared->u8SD); 720 742 } 743 #endif 721 744 722 745 /* 723 746 * Updates an HDA stream's current read or write buffer position (depending on the stream type) by 724 * updating its associated LPIB register and DMA position buffer (if enabled).747 * setting its associated LPIB register and DMA position buffer (if enabled) to an absolute value. 725 748 * 726 749 * @param pStreamShared HDA stream to update read / write position for (shared). 727 750 * @param pDevIns The device instance. 728 751 * @param pThis The shared HDA device state. 729 * @param u 32LPIBAbsolute position (in bytes) to set current read / write position to.730 */ 731 static void hdaR3StreamSetPosition (PHDASTREAM pStreamShared, PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t u32LPIB)752 * @param uLPIB Absolute position (in bytes) to set current read / write position to. 753 */ 754 static void hdaR3StreamSetPositionAbs(PHDASTREAM pStreamShared, PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t uLPIB) 732 755 { 733 756 AssertPtrReturnVoid(pStreamShared); 734 735 Log3Func(("[SD%RU8] LPIB=%RU32 (DMA Position Buffer Enabled: %RTbool)\n", pStreamShared->u8SD, u32LPIB, pThis->fDMAPosition)); 757 AssertReturnVoid (uLPIB <= pStreamShared->u32CBL); /* Make sure that we don't go out-of-bounds. */ 758 759 Log3Func(("[SD%RU8] LPIB=%RU32 (DMA Position Buffer Enabled: %RTbool)\n", pStreamShared->u8SD, uLPIB, pThis->fDMAPosition)); 736 760 737 761 /* Update LPIB in any case. */ 738 HDA_STREAM_REG(pThis, LPIB, pStreamShared->u8SD) = u 32LPIB;762 HDA_STREAM_REG(pThis, LPIB, pStreamShared->u8SD) = uLPIB; 739 763 740 764 /* Do we need to tell the current DMA position? */ … … 743 767 int rc2 = PDMDevHlpPCIPhysWrite(pDevIns, 744 768 pThis->u64DPBase + (pStreamShared->u8SD * 2 * sizeof(uint32_t)), 745 (void *)&u 32LPIB, sizeof(uint32_t));769 (void *)&uLPIB, sizeof(uint32_t)); 746 770 AssertRC(rc2); 747 771 } 772 } 773 774 /* 775 * Updates an HDA stream's current read or write buffer position (depending on the stream type) by 776 * adding a value to its associated LPIB register and DMA position buffer (if enabled). 777 * 778 * @note Handles automatic CBL wrap-around. 779 * 780 * @param pStreamShared HDA stream to update read / write position for (shared). 781 * @param pDevIns The device instance. 782 * @param pThis The shared HDA device state. 783 * @param uToAdd Position (in bytes) to add to the current read / write position. 784 */ 785 void hdaR3StreamSetPositionAdd(PHDASTREAM pStreamShared, PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t uToAdd) 786 { 787 if (!uToAdd) /* No need to update anything if 0. */ 788 return; 789 790 hdaR3StreamSetPositionAbs(pStreamShared, pDevIns, pThis, 791 (HDA_STREAM_REG(pThis, LPIB, pStreamShared->u8SD) + uToAdd) % pStreamShared->u32CBL); 748 792 } 749 793 … … 941 985 if (pcbRead) 942 986 *pcbRead = cbReadTotal; 987 988 return rc; 989 } 990 991 /* 992 * Reads DMA data from a given HDA output stream. 993 * 994 * @return IPRT status code. 995 * @param pDevIns The device instance. 996 * @param pThis The shared HDA device state (for stats). 997 * @param pStreamShared HDA output stream to read DMA data from - shared bits. 998 * @param pStreamR3 HDA output stream to read DMA data from - shared ring-3. 999 * @param pvBuf Where to store the read data. 1000 * @param cbBuf How much to read in bytes. 1001 * @param pcbRead Returns read bytes from DMA. Optional. 1002 */ 1003 int hdaR3DMARead2(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTREAM pStreamShared, PHDASTREAMR3 pStreamR3, 1004 void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead) 1005 { 1006 RT_NOREF(pThis); 1007 PHDABDLE pBDLE = &pStreamShared->State.BDLE; 1008 1009 int rc = VINF_SUCCESS; 1010 1011 uint32_t cbReadTotal = 0; 1012 uint32_t cbLeft = RT_MIN(cbBuf, pBDLE->Desc.u32BufSize - pBDLE->State.u32BufOff); 1013 1014 # ifdef HDA_DEBUG_SILENCE 1015 uint64_t csSilence = 0; 1016 1017 pStreamR3->Dbg.cSilenceThreshold = 100; 1018 pStreamR3->Dbg.cbSilenceReadMin = _1M; 1019 # endif 1020 1021 RTGCPHYS GCPhysChunk = pBDLE->Desc.u64BufAddr + pBDLE->State.u32BufOff; 1022 1023 while (cbLeft) 1024 { 1025 uint32_t cbChunk = RT_MIN(cbLeft, pStreamShared->u8FIFOS); 1026 1027 rc = PDMDevHlpPhysRead(pDevIns, GCPhysChunk, (uint8_t *)pvBuf + cbReadTotal, cbChunk); 1028 AssertRCBreak(rc); 1029 1030 # ifdef HDA_DEBUG_SILENCE 1031 uint16_t *pu16Buf = (uint16_t *)pvBuf; 1032 for (size_t i = 0; i < cbChunk / sizeof(uint16_t); i++) 1033 { 1034 if (*pu16Buf == 0) 1035 csSilence++; 1036 else 1037 break; 1038 pu16Buf++; 1039 } 1040 # endif 1041 1042 /* 1043 * Update the stream's current position. 1044 * Do this as accurate and close to the actual data transfer as possible. 1045 * All guetsts rely on this, depending on the mechanism they use (LPIB register or DMA counters). 1046 */ 1047 hdaR3StreamSetPositionAdd(pStreamShared, pDevIns, pThis, /* cbChunk */ 0); 1048 1049 if (RT_LIKELY(!pStreamR3->Dbg.Runtime.fEnabled)) 1050 { /* likely */ } 1051 else 1052 DrvAudioHlpFileWrite(pStreamR3->Dbg.Runtime.pFileDMARaw, (uint8_t *)pvBuf + cbReadTotal, cbChunk, 0 /* fFlags */); 1053 1054 STAM_COUNTER_ADD(&pThis->StatBytesRead, cbChunk); 1055 1056 /* advance */ 1057 Assert(cbLeft >= cbChunk); 1058 GCPhysChunk = (GCPhysChunk + cbChunk) % pBDLE->Desc.u32BufSize; 1059 cbReadTotal += cbChunk; 1060 cbLeft -= cbChunk; 1061 } 1062 1063 # ifdef HDA_DEBUG_SILENCE 1064 if (csSilence) 1065 pStreamR3->Dbg.csSilence += csSilence; 1066 1067 if ( csSilence == 0 1068 && pStreamR3->Dbg.csSilence > pStreamR3->Dbg.cSilenceThreshold 1069 && pStreamR3->Dbg.cbReadTotal >= pStreamR3->Dbg.cbSilenceReadMin) 1070 { 1071 LogFunc(("Silent block detected: %RU64 audio samples\n", pStreamR3->Dbg.csSilence)); 1072 pStreamR3->Dbg.csSilence = 0; 1073 } 1074 # endif 1075 1076 if (RT_SUCCESS(rc)) 1077 { 1078 if (pcbRead) 1079 *pcbRead = cbReadTotal; 1080 } 943 1081 944 1082 return rc; … … 966 1104 PHDASTREAMR3 pStreamR3, uint32_t cbToProcessMax, bool fInTimer) 967 1105 { 1106 LogFlowFuncEnter(); 1107 968 1108 uint8_t const uSD = pStreamShared->u8SD; 969 1109 hdaR3StreamLock(pStreamR3); … … 974 1114 bool fProceed = true; 975 1115 976 /* Stream not running ? */1116 /* Stream not running (anymore)? */ 977 1117 if (!pStreamShared->State.fRunning) 978 1118 { 979 Log3Func(("[SD%RU8] Not running \n", uSD));1119 Log3Func(("[SD%RU8] Not running, skipping transfer\n", uSD)); 980 1120 fProceed = false; 981 1121 } 1122 982 1123 else if (HDA_STREAM_REG(pThis, STS, uSD) & HDA_SDSTS_BCIS) 983 1124 { 984 Log3Func(("[SD%RU8] BCIS bit set\n", uSD)); 1125 Log3Func(("[SD%RU8] BCIS bit set, skipping transfer\n", uSD)); 1126 #ifdef HDA_STRICT 1127 /* Timing emulation bug or guest is misbehaving -- let me know. */ 1128 AssertMsgFailed(("BCIS bit for stream #%RU8 still set when it shouldn't\n", uSD)); 1129 #endif 985 1130 fProceed = false; 986 1131 } … … 1006 1151 pStreamShared->State.tsTransferLast = tsNow; 1007 1152 1008 /* Sanity checks. */1153 /* Register sanity checks. */ 1009 1154 Assert(uSD < HDA_MAX_STREAMS); 1010 1155 Assert(pStreamShared->u64BDLBase); … … 1014 1159 /* State sanity checks. */ 1015 1160 Assert(ASMAtomicReadBool(&pStreamShared->State.fInReset) == false); 1161 Assert(ASMAtomicReadBool(&pStreamShared->State.fRunning)); 1162 1163 /* Transfer sanity checks. */ 1164 Assert(pStreamShared->State.cbTransferSize); 1165 Assert(pStreamShared->State.cbTransferChunk <= pStreamShared->State.cbTransferSize); 1016 1166 1017 1167 int rc = VINF_SUCCESS; … … 1025 1175 } 1026 1176 1027 uint32_t cbToProcess = RT_MIN(pStreamShared->State.cbTransferSize - pStreamShared->State.cbTransferProcessed, 1028 pStreamShared->State.cbTransferChunk); 1029 1030 Log3Func(("[SD%RU8] cbToProcess=%RU32, cbToProcessMax=%RU32\n", uSD, cbToProcess, cbToProcessMax)); 1031 1032 if (cbToProcess > cbToProcessMax) 1033 { 1034 LogFunc(("[SD%RU8] Limiting transfer (cbToProcess=%RU32, cbToProcessMax=%RU32)\n", uSD, cbToProcess, cbToProcessMax)); 1035 1036 /* Never process more than a stream currently can handle. */ 1037 cbToProcess = cbToProcessMax; 1038 } 1177 uint32_t cbToProcess = RT_MIN(pStreamShared->State.cbTransferSize, pStreamShared->State.cbTransferChunk); 1178 1179 Assert(cbToProcess); /* Nothing to process when there should be data. Accounting bug? */ 1180 AssertStmt(cbToProcess <= cbToProcessMax, cbToProcess = cbToProcessMax); /* More data to process than maximum allowed. */ 1039 1181 1040 1182 uint32_t cbProcessed = 0; … … 1053 1195 if (pStreamShared->State.cfPosAdjustLeft) 1054 1196 cbChunk = RT_MIN(cbChunk, uint32_t(pStreamShared->State.cfPosAdjustLeft * pStreamR3->State.Mapping.cbFrameSize)); 1055 1056 Log3Func(("[SD%RU8] cbChunk=%RU32, cPosAdjustFramesLeft=%RU16\n",1057 uSD, cbChunk, pStreamShared->State.cfPosAdjustLeft));1058 1197 1059 1198 if (!cbChunk) … … 1261 1400 if (cbDMA) 1262 1401 { 1263 const size_t cbCircBufUsed = RTCircBufUsed(pCircBuf); RT_NOREF(cbCircBufUsed);1264 1265 Log3Func(("[SD%RU8] cbDMA=%RU32, cbUsed=%zu, uFIFOW=%RU8, uFIFOS=%RU8\n",1266 uSD, cbDMA, cbCircBufUsed, pStreamShared->u8FIFOW, pStreamShared->u8FIFOS));1267 1268 1402 /* We always increment the position of DMA buffer counter because we're always reading 1269 1403 * into an intermediate DMA buffer. */ … … 1281 1415 } 1282 1416 1417 Log3Func(("[SD%RU8] cbDMA=%RU32 -> %R[bdle]\n", uSD, cbDMA, pBDLE)); 1418 } 1419 1420 if (hdaR3BDLEIsComplete(pBDLE)) 1421 { 1422 Log3Func(("[SD%RU8] Completed %R[bdle]\n", uSD, pBDLE)); 1423 1424 /* Make sure to also update the wall clock when a BDLE is complete. 1425 * Needed for Windows 10 guests. */ 1426 hdaR3WalClkSet(pThis, pThisCC, 1427 hdaWalClkGetCurrent(pThis) 1428 + hdaR3StreamPeriodFramesToWalClk(pPeriod, 1429 pBDLE->Desc.u32BufSize 1430 / pStreamR3->State.Mapping.cbFrameSize), 1431 false /* fForce */); 1432 1283 1433 /* 1284 1434 * Update the stream's current position. 1285 1435 * Do this as accurate and close to the actual data transfer as possible. 1286 1436 * All guetsts rely on this, depending on the mechanism they use (LPIB register or DMA counters). 1437 * 1438 * Note for Windows 10: The OS' driver is *very* picky about *when* the (DMA) positions get updated! 1439 * Not doing this at the right time will result in ugly sound crackles! 1287 1440 */ 1288 uint32_t cbStreamPos = hdaR3StreamGetPosition(pThis, pStreamShared); 1289 if (cbStreamPos == pStreamShared->u32CBL) 1290 cbStreamPos = 0; 1291 1292 hdaR3StreamSetPosition(pStreamShared, pDevIns, pThis, cbStreamPos + cbDMA); 1293 } 1294 1295 if (hdaR3BDLEIsComplete(pBDLE)) 1296 { 1297 Log3Func(("[SD%RU8] Complete: %R[bdle]\n", uSD, pBDLE)); 1441 hdaR3StreamSetPositionAdd(pStreamShared, pDevIns, pThis, pBDLE->Desc.u32BufSize); 1298 1442 1299 1443 /* Does the current BDLE require an interrupt to be sent? */ … … 1316 1460 ("Too many pending interrupts (%RU8) for stream #%RU8\n", 1317 1461 pStreamShared->State.cTransferPendingInterrupts, uSD)); 1462 1463 /* Assert the interrupt before actually fetching the next BDLE below. */ 1464 if (pStreamShared->State.cTransferPendingInterrupts) 1465 { 1466 Log3Func(("[SD%RU8] Scheduling interrupt (now %RU8 total)\n", uSD, pStreamShared->State.cTransferPendingInterrupts)); 1467 1468 /* 1469 * Set the stream's BCIS bit. 1470 * 1471 * Note: This only must be done if the whole period is complete, and not if only 1472 * one specific BDL entry is complete (if it has the IOC bit set). 1473 * 1474 * This will otherwise confuses the guest when it 1) deasserts the interrupt, 1475 * 2) reads SDSTS (with BCIS set) and then 3) too early reads a (wrong) WALCLK value. 1476 * 1477 * snd_hda_intel on Linux will tell. 1478 */ 1479 HDA_STREAM_REG(pThis, STS, uSD) |= HDA_SDSTS_BCIS; 1480 1481 /* Trigger an interrupt first and let hdaRegWriteSDSTS() deal with 1482 * ending / beginning a period. */ 1483 HDA_PROCESS_INTERRUPT(pDevIns, pThis); 1484 } 1318 1485 } 1319 1486 } … … 1338 1505 } 1339 1506 1340 Log3Func(("[SD%RU8] cbToProcess=%RU32, cbProcessed=%RU32, cbLeft=%RU32, %R[bdle], rc=%Rrc\n",1341 uSD, cbToProcess, cbProcessed, cbLeft, pBDLE, rc));1342 1343 1507 /* Sanity. */ 1344 1508 Assert(cbProcessed == cbToProcess); … … 1351 1515 hdaR3StreamPeriodInc(pPeriod, RT_MIN(cbProcessed / pStreamR3->State.Mapping.cbFrameSize, 1352 1516 hdaR3StreamPeriodGetRemainingFrames(pPeriod))); 1353 1354 pStreamShared->State.cbTransferProcessed += cbProcessed; 1355 } 1356 1357 /* Make sure that we never report more stuff processed than initially announced. */ 1358 if (pStreamShared->State.cbTransferProcessed > pStreamShared->State.cbTransferSize) 1359 pStreamShared->State.cbTransferProcessed = pStreamShared->State.cbTransferSize; 1360 1361 uint32_t cbTransferLeft = pStreamShared->State.cbTransferSize - pStreamShared->State.cbTransferProcessed; 1362 bool fTransferComplete = !cbTransferLeft; 1363 uint64_t tsTransferNext = 0; 1517 } 1518 1519 const bool fTransferComplete = cbLeft == 0; 1520 uint64_t tsTransferNext = 0; 1364 1521 1365 1522 if (fTransferComplete) … … 1380 1537 hdaWalClkGetCurrent(pThis) 1381 1538 + hdaR3StreamPeriodFramesToWalClk(pPeriod, 1382 pStreamShared->State.cbTransferProcessed1539 cbProcessed 1383 1540 / pStreamR3->State.Mapping.cbFrameSize), 1384 1541 false /* fForce */); … … 1387 1544 1388 1545 /* Does the period have any interrupts outstanding? */ 1389 if (pStreamShared->State.cTransferPendingInterrupts) 1390 { 1391 Log3Func(("[SD%RU8] Scheduling interrupt\n", uSD)); 1392 1393 /* 1394 * Set the stream's BCIS bit. 1395 * 1396 * Note: This only must be done if the whole period is complete, and not if only 1397 * one specific BDL entry is complete (if it has the IOC bit set). 1398 * 1399 * This will otherwise confuses the guest when it 1) deasserts the interrupt, 1400 * 2) reads SDSTS (with BCIS set) and then 3) too early reads a (wrong) WALCLK value. 1401 * 1402 * snd_hda_intel on Linux will tell. 1403 */ 1404 HDA_STREAM_REG(pThis, STS, uSD) |= HDA_SDSTS_BCIS; 1405 1406 /* Trigger an interrupt first and let hdaRegWriteSDSTS() deal with 1407 * ending / beginning a period. */ 1408 HDA_PROCESS_INTERRUPT(pDevIns, pThis); 1409 } 1410 else /* Transfer still in-flight -- schedule the next timing slot. */ 1411 { 1412 uint32_t cbTransferNext = cbTransferLeft; 1413 1414 /* No data left to transfer anymore or do we have more data left 1415 * than we can transfer per timing slot? Clamp. */ 1416 if ( !cbTransferNext 1417 || cbTransferNext > pStreamShared->State.cbTransferChunk) 1418 { 1419 cbTransferNext = pStreamShared->State.cbTransferChunk; 1420 } 1421 1422 tsTransferNext = tsNow + (cbTransferNext * pStreamShared->State.cTicksPerByte); 1423 1424 /* 1425 * If the current transfer is complete, reset our counter. 1426 * 1427 * This can happen for examlpe if the guest OS (like macOS) sets up 1428 * big BDLEs without IOC bits set (but for the last one) and the 1429 * transfer is complete before we reach such a BDL entry. 1430 */ 1431 if (fTransferComplete) 1432 pStreamShared->State.cbTransferProcessed = 0; 1546 if (!pStreamShared->State.cTransferPendingInterrupts) 1547 { 1548 /* No, set relative timer ticks for the next transfer to happen. 1549 * This must happen at a constant rate. */ 1550 tsTransferNext = pStreamShared->State.cTransferTicks; 1433 1551 } 1434 1552 … … 1436 1554 if (tsTransferNext) /* Can be 0 if no next transfer is needed. */ 1437 1555 { 1438 Log3Func(("[SD%RU8] Scheduling timer\n", uSD)); 1439 1440 LogFunc(("Timer set SD%RU8\n", uSD)); 1556 Log3Func(("[SD%RU8] Scheduling timer @ %RU64\n", uSD, tsNow + tsTransferNext)); 1557 1441 1558 Assert(!fInTimer || tsNow == PDMDevHlpTimerGet(pDevIns, pStreamShared->hTimer)); 1442 1559 hdaR3TimerSet(pDevIns, pStreamShared, tsTransferNext, … … 1448 1565 pStreamShared->State.tsTransferLast = tsNow; 1449 1566 1450 Log3Func(("[SD%RU8] cbTransferLeft=%RU32-- %RU32/%RU32\n",1451 uSD, cbTransferLeft, pStreamShared->State.cbTransferProcessed, pStreamShared->State.cbTransferSize));1567 Log3Func(("[SD%RU8] %R[bdle] -- %RU32/%RU32\n", 1568 uSD, pBDLE, cbProcessed, pStreamShared->State.cbTransferSize)); 1452 1569 Log3Func(("[SD%RU8] fTransferComplete=%RTbool, cTransferPendingInterrupts=%RU8\n", 1453 1570 uSD, fTransferComplete, pStreamShared->State.cTransferPendingInterrupts)); 1454 1571 Log3Func(("[SD%RU8] tsNow=%RU64, tsTransferNext=%RU64 (in %RU64 ticks)\n", 1455 uSD, tsNow, tsTransferNext, tsTransferNext - tsNow)); 1572 uSD, tsNow, tsTransferNext, tsTransferNext ? tsTransferNext - tsNow : 0)); 1573 1574 LogFlowFuncLeave(); 1456 1575 1457 1576 hdaR3StreamPeriodUnlock(pPeriod); … … 1509 1628 # endif 1510 1629 { 1511 const uint32_t cbStreamFree = hdaR3StreamGetFree(pStreamR3); 1512 if (cbStreamFree) 1513 { 1514 /* Do the DMA transfer. */ 1515 rc2 = hdaR3StreamTransfer(pDevIns, pThis, pThisCC, pStreamShared, pStreamR3, cbStreamFree, fInTimer); 1516 AssertRC(rc2); 1517 } 1630 1631 uint32_t cbStreamFree = hdaR3StreamGetFree(pStreamR3); 1632 if (!cbStreamFree) 1633 { 1634 LogRel2(("HDA: Warning: Hit stream #%RU8 overflow, dropping audio data\n", pStreamShared->u8SD)); 1635 # ifdef HDA_STRICT 1636 AssertMsgFailed(("Hit stream #%RU8 overflow -- timing bug?\n", pStreamShared->u8SD)); 1637 # endif 1638 /* When hitting an overflow, drop all remaining data to make space for current data. 1639 * This is needed in order to keep the device emulation running at a constant rate, 1640 * at the cost of losing old data. */ 1641 RTCircBufReset(pStreamR3->State.pCircBuf); 1642 cbStreamFree = hdaR3StreamGetFree(pStreamR3); 1643 } 1644 1645 /* Do the DMA transfer. */ 1646 rc2 = hdaR3StreamTransfer(pDevIns, pThis, pThisCC, pStreamShared, pStreamR3, cbStreamFree, fInTimer); 1647 AssertRC(rc2); 1648 1649 const uint64_t tsNowNs = RTTimeNanoTS(); 1650 1651 /* Never updated yet? Set initial timestamp. */ 1652 if (pStreamShared->State.tsLastUpdateNs == 0) 1653 pStreamShared->State.tsLastUpdateNs = tsNowNs; 1518 1654 1519 1655 /* Only read from the HDA stream at the given scheduling rate. */ 1520 const uint64_t tsNowNs = RTTimeNanoTS();1521 1656 if (tsNowNs - pStreamShared->State.tsLastUpdateNs >= pStreamShared->State.Cfg.Device.cMsSchedulingHint * RT_NS_1MS) 1522 1657 { … … 1524 1659 pStreamShared->State.tsLastUpdateNs = tsNowNs; 1525 1660 } 1661 1662 # ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO 1526 1663 } 1527 1528 Log3Func(("[SD%RU8] fInTimer=%RTbool, fDoRead=%RTbool\n", pStreamShared->u8SD, fInTimer, fDoRead)); 1664 # endif 1665 Log3Func(("[SD%RU8] fInTimer=%RTbool, tsLastUpdateNs=%RU64, fDoRead=%RTbool\n", 1666 pStreamShared->u8SD, fInTimer, pStreamShared->State.tsLastUpdateNs, fDoRead)); 1529 1667 1530 1668 # ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO -
trunk/src/VBox/Devices/Audio/HDAStream.h
r87319 r87567 136 136 /** Transfer chunk size (in bytes) of a transfer period. */ 137 137 uint32_t cbTransferChunk; 138 /** How many bytes already have been processed in within139 * the current transfer period. */140 uint32_t cbTransferProcessed;141 138 /** How many interrupts are pending due to 142 139 * BDLE interrupt-on-completion (IOC) bits set. */ 143 140 uint8_t cTransferPendingInterrupts; 144 uint8_t abPadding2[ 3];141 uint8_t abPadding2[7]; 145 142 /** The stream's timer Hz rate. 146 143 * This value can can be different from the device's default Hz rate, … … 280 277 PHDASTREAM pStreamShared, PHDASTREAMR3 pStreamR3, uint8_t uSD); 281 278 int hdaR3StreamEnable(PHDASTREAM pStreamShared, PHDASTREAMR3 pStreamR3, bool fEnable); 282 /* uint32_t hdaR3StreamGetPosition(PHDASTATE pThis, PHDASTREAMR3 pStreamShared); - only used in HDAStream.cpp */ 283 /*void hdaR3StreamSetPosition(PHDASTREAM pStream, PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t u32LPIB); - only used in HDAStream.cpp */ 284 /*uint32_t hdaR3StreamGetFree(PHDASTREAM pStream); - only used in HDAStream.cpp */ 285 /*uint32_t hdaR3StreamGetUsed(PHDASTREAM pStream); - only used in HDAStream.cpp */ 279 void hdaR3StreamSetPositionAdd(PHDASTREAM pStreamShared, PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t uToAdd); 286 280 bool hdaR3StreamTransferIsScheduled(PHDASTREAM pStreamShared, uint64_t tsNow); 287 281 uint64_t hdaR3StreamTransferGetNext(PHDASTREAM pStreamShared);
Note:
See TracChangeset
for help on using the changeset viewer.