Changeset 88158 in vbox for trunk/src/VBox
- Timestamp:
- Mar 17, 2021 2:39:22 PM (4 years ago)
- svn:sync-xref-src-repo-rev:
- 143307
- Location:
- trunk/src/VBox/Devices/Audio
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Audio/DevHDA.cpp
r88140 r88158 1440 1440 AssertRC(rc2); 1441 1441 1442 /* Avoid going through the timer here by calling the stream's timer function directly. 1443 * Should speed up starting the stream transfers. */ 1444 uint64_t tsNow = hdaR3StreamTimerMain(pDevIns, pThis, pThisCC, pStreamShared, pStreamR3); 1445 1442 /** @todo move this into a HDAStream.cpp function. */ 1443 uint64_t tsNow; 1444 if (hdaGetDirFromSD(uSD) == PDMAUDIODIR_OUT) 1445 { 1446 /* Output streams: Avoid going through the timer here by calling the stream's timer 1447 function directly. Should speed up starting the stream transfers. */ 1448 tsNow = hdaR3StreamTimerMain(pDevIns, pThis, pThisCC, pStreamShared, pStreamR3); 1449 } 1450 else 1451 { 1452 /* Input streams: Arm the timer and kick the AIO thread. */ 1453 tsNow = PDMDevHlpTimerGet(pDevIns, pStreamShared->hTimer); 1454 uint64_t tsTransferNext = tsNow + pStreamShared->State.aSchedule[0].cPeriodTicks; 1455 pStreamShared->State.tsTransferNext = tsTransferNext; /* legacy */ 1456 pStreamShared->State.cbTransferSize = pStreamShared->State.aSchedule[0].cbPeriod; 1457 Log3Func(("[SD%RU8] tsTransferNext=%RU64 (in %RU64)\n", 1458 pStreamShared->u8SD, tsTransferNext, tsTransferNext - tsNow)); 1459 int rc = PDMDevHlpTimerSet(pDevIns, pStreamShared->hTimer, tsTransferNext); 1460 AssertRC(rc); 1461 1462 /** @todo we should have a delayed AIO thread kick off, really... */ 1463 hdaR3StreamAsyncIONotify(pStreamR3); 1464 } 1446 1465 hdaR3StreamMarkStarted(pDevIns, pThis, pStreamShared, tsNow); 1447 1466 } … … 5248 5267 "Number of internal DMA buffer overflows.", "Stream%u/DMABufferOverflows", idxStream); 5249 5268 else 5269 { 5250 5270 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aStreams[idxStream].State.StatDmaFlowErrors, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES, 5251 5271 "Number of internal DMA buffer underuns.", "Stream%u/DMABufferUnderruns", idxStream); 5272 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aStreams[idxStream].State.StatDmaFlowErrorBytes, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_BYTES, 5273 "Number of bytes of silence added to cope with underruns.", "Stream%u/DMABufferSilence", idxStream); 5274 } 5252 5275 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aStreams[idxStream].State.offRead, STAMTYPE_U64, STAMVISIBILITY_USED, STAMUNIT_BYTES, 5253 5276 "Virtual internal buffer read position.", "Stream%u/offRead", idxStream); -
trunk/src/VBox/Devices/Audio/HDAStream.cpp
r88137 r88158 49 49 50 50 static int hdaR3StreamAsyncIODestroy(PHDASTREAMR3 pStreamR3); 51 static int hdaR3StreamAsyncIONotify(PHDASTREAMR3 pStreamR3);52 51 53 52 … … 654 653 655 654 pStreamShared->State.cbAvgTransfer = (uint32_t)(cbTotal + cPeriods - 1) / cPeriods; 655 656 /* For input streams we must determin a pre-buffering requirement. 657 We use the initial delay as a basis here, though we must have at 658 least two max periods worth of data queued up due to the way we 659 work the AIO thread. */ 660 pStreamShared->State.fInputPreBuffered = false; 661 pStreamShared->State.cbInputPreBuffer = PDMAudioPropsMilliToBytes(&pCfg->Props, pThis->msInitialDelay); 662 pStreamShared->State.cbInputPreBuffer = RT_MIN(cbMaxPeriod * 2, pStreamShared->State.cbInputPreBuffer); 656 663 657 664 /* … … 838 845 pStreamShared->State.idxSchedule = 0; 839 846 pStreamShared->State.idxScheduleLoop = 0; 847 pStreamShared->State.fInputPreBuffered = false; 840 848 841 849 if (pStreamR3->State.pCircBuf) … … 1049 1057 1050 1058 /** 1051 * Writes audio data from a mixer sink into an HDA stream's DMA buffer.1052 *1053 * @returns IPRT status code.1054 * @param pStreamR3 HDA stream to write to (ring-3).1055 * @param pvBuf Data buffer to write.1056 * If NULL, silence will be written.1057 * @param cbBuf Number of bytes of data buffer to write.1058 * @param pcbWritten Number of bytes written. Optional.1059 */1060 static int hdaR3StreamWrite(PHDASTREAMR3 pStreamR3, const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten)1061 {1062 Assert(cbBuf);1063 1064 PRTCIRCBUF pCircBuf = pStreamR3->State.pCircBuf;1065 AssertPtr(pCircBuf);1066 1067 uint32_t cbWrittenTotal = 0;1068 uint32_t cbLeft = RT_MIN(cbBuf, (uint32_t)RTCircBufFree(pCircBuf));1069 1070 while (cbLeft)1071 {1072 void *pvDst;1073 size_t cbDst;1074 RTCircBufAcquireWriteBlock(pCircBuf, cbLeft, &pvDst, &cbDst);1075 1076 if (cbDst)1077 {1078 if (pvBuf)1079 memcpy(pvDst, (uint8_t *)pvBuf + cbWrittenTotal, cbDst);1080 else /* Send silence. */1081 {1082 /** @todo Use a sample spec for "silence" based on the PCM parameters.1083 * For now we ASSUME that silence equals NULLing the data. */1084 RT_BZERO(pvDst, cbDst);1085 }1086 #ifdef VBOX_WITH_DTRACE1087 VBOXDD_HDA_STREAM_AIO_IN((uint32_t)pStreamR3->u8SD, (uint32_t)cbDst, pStreamR3->State.offWrite);1088 #endif1089 pStreamR3->State.offWrite += cbDst;1090 1091 if (RT_LIKELY(!pStreamR3->Dbg.Runtime.fEnabled))1092 { /* likely */ }1093 else1094 DrvAudioHlpFileWrite(pStreamR3->Dbg.Runtime.pFileStream, pvDst, cbDst, 0 /* fFlags */);1095 }1096 1097 RTCircBufReleaseWriteBlock(pCircBuf, cbDst);1098 1099 Assert(cbLeft >= (uint32_t)cbDst);1100 cbLeft -= (uint32_t)cbDst;1101 cbWrittenTotal += (uint32_t)cbDst;1102 }1103 1104 Log3Func(("cbWrittenTotal=%#RX32 @ %#RX64\n", cbWrittenTotal, pStreamR3->State.offWrite - cbWrittenTotal));1105 1106 if (pcbWritten)1107 *pcbWritten = cbWrittenTotal;1108 1109 return VINF_SUCCESS;1110 }1111 1112 1113 /**1114 1059 * Reads audio data from an HDA stream's DMA buffer and writes into a specified mixer sink. 1115 1060 * … … 1274 1219 * @param pStreamShared HDA stream to update (shared). 1275 1220 * @param pStreamR3 HDA stream to update (ring-3). 1276 * @param cbToProcessMax How much data (in bytes) to process as maximum. 1221 * @param cbToConsume The max amount of data to consume from the 1222 * internal DMA buffer. The caller will make sure 1223 * this is always the transfer size fo the current 1224 * period (unless something is seriously wrong). 1225 * @param fWriteSilence Whether to feed the guest silence rather than 1226 * fetching bytes from the internal DMA buffer. 1227 * This is set initially while we pre-buffer a 1228 * little bit of input, so we can better handle 1229 * time catch-ups and other schduling fun. 1230 * @param tsNowNs The current RTTimeNano() value. 1231 * 1232 * @remarks Caller owns the stream lock. 1277 1233 */ 1278 1234 static int hdaR3StreamDoDmaInput(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTATER3 pThisCC, PHDASTREAM pStreamShared, 1279 PHDASTREAMR3 pStreamR3, uint32_t cbTo ProcessMax)1235 PHDASTREAMR3 pStreamR3, uint32_t cbToConsume, bool fWriteSilence, uint64_t tsNowNs) 1280 1236 { 1281 1237 uint8_t const uSD = pStreamShared->u8SD; 1282 LogFlowFunc(("ENTER - #%u cbToProcessMax=%#x\n", uSD, cbToProcessMax)); 1283 Assert(hdaGetDirFromSD(uSD) != PDMAUDIODIR_OUT); 1284 1285 if (RT_LIKELY(cbToProcessMax >= pStreamShared->State.cbTransferSize)) 1286 { /*likely*/ } 1238 LogFlowFunc(("ENTER - #%u cbToConsume=%#x%s\n", uSD, cbToConsume, fWriteSilence ? " silence" : "")); 1239 1240 1241 /* 1242 * Check if we should skip town... 1243 */ 1244 1245 /* Stream not running (anymore)? */ 1246 if (pStreamShared->State.fRunning) 1247 { /* likely */ } 1287 1248 else 1288 1249 { 1289 /** @todo account for this or something so we can try get back in sync1290 * later... */1291 LogFlowFunc(("Internal DMA/AIO buffer %s (%#x, wanted at least %#x)\n",1292 hdaGetDirFromSD(uSD) == PDMAUDIODIR_OUT ? "overflow" : "underflow",1293 cbToProcessMax, pStreamShared->State.cbTransferSize));1294 STAM_REL_COUNTER_INC(&pStreamR3->State.StatDmaFlowErrors);1295 #ifdef VBOX_WITH_DTRACE1296 VBOXDD_HDA_STREAM_DMA_FLOWERROR(uSD, cbToProcessMax, pStreamShared->State.cbTransferSize,1297 hdaGetDirFromSD(uSD) == PDMAUDIODIR_OUT ? 1 : 0);1298 #endif1299 }1300 1301 hdaStreamLock(pStreamShared);1302 1303 PHDASTREAMPERIOD pPeriod = &pStreamShared->State.Period;1304 1305 bool fProceed = true;1306 1307 /* Stream not running (anymore)? */1308 if (!pStreamShared->State.fRunning)1309 {1310 1250 Log3Func(("[SD%RU8] Not running, skipping transfer\n", uSD)); 1311 fProceed = false; 1312 } 1313 1314 else if (HDA_STREAM_REG(pThis, STS, uSD) & HDA_SDSTS_BCIS) 1251 return VINF_SUCCESS; 1252 } 1253 1254 if (!(HDA_STREAM_REG(pThis, STS, uSD) & HDA_SDSTS_BCIS)) 1255 { /* likely */ } 1256 else 1315 1257 { 1316 1258 Log3Func(("[SD%RU8] BCIS bit set, skipping transfer\n", uSD)); … … 1319 1261 AssertMsgFailed(("BCIS bit for stream #%RU8 still set when it shouldn't\n", uSD)); 1320 1262 #endif 1321 fProceed = false;1322 }1323 1324 if (!fProceed)1325 {1326 hdaStreamUnlock(pStreamShared);1327 1263 return VINF_SUCCESS; 1328 1264 } 1329 1265 1330 /* Update real-time timestamp. */ 1331 const uint64_t tsNowNs = RTTimeNanoTS(); 1332 #ifdef LOG_ENABLED 1333 const uint64_t tsDeltaMs = (tsNowNs - pStreamShared->State.tsLastTransferNs) / RT_NS_1MS; 1334 Log3Func(("[SD%RU8] tsDeltaNs=%RU64ms\n", uSD, tsDeltaMs)); 1335 #endif 1336 pStreamShared->State.tsLastTransferNs = tsNowNs; 1337 1338 const uint64_t tsNow = PDMDevHlpTimerGet(pDevIns, pStreamShared->hTimer); 1339 1340 if (!pStreamShared->State.tsTransferLast) 1341 pStreamShared->State.tsTransferLast = tsNow; 1342 1343 pStreamShared->State.tsTransferLast = tsNow; 1344 1266 /* 1267 * Stream sanity checks. 1268 */ 1345 1269 /* Register sanity checks. */ 1346 1270 Assert(uSD < HDA_MAX_STREAMS); … … 1353 1277 Assert(ASMAtomicReadBool(&pStreamShared->State.fRunning)); 1354 1278 1355 /* Transfer sanity checks. */ 1356 Assert(pStreamShared->State.cbTransferSize); 1357 1358 int rc = VINF_SUCCESS; 1359 1360 uint32_t cbToProcess = pStreamShared->State.cbTransferSize; 1361 1362 Assert(cbToProcess); /* Nothing to process when there should be data. Accounting bug? */ 1363 1364 /* More data to process than maximum allowed? */ 1365 #ifdef HDA_STRICT 1366 AssertStmt(cbToProcess <= cbToProcessMax, cbToProcess = cbToProcessMax); 1367 #else 1368 if (cbToProcess > cbToProcessMax) 1369 cbToProcess = cbToProcessMax; 1279 /* 1280 * Some timestamp stuff for logging/debugging. 1281 */ 1282 /*const uint64_t tsNowNs = RTTimeNanoTS();*/ 1283 Log3Func(("[SD%RU8] tsDeltaNs=%'RU64 ns\n", uSD, tsNowNs - pStreamShared->State.tsLastTransferNs)); 1284 pStreamShared->State.tsLastTransferNs = tsNowNs; 1285 pStreamShared->State.tsTransferLast = PDMDevHlpTimerGet(pDevIns, pStreamShared->hTimer); 1286 1287 /* 1288 * Set the FIFORDY bit on the stream while doing the transfer. 1289 */ 1290 /** @todo r=bird: I don't get the HDA_SDSTS_FIFORDY logic. Unless we're 1291 * assuming SMP guest and that it can get stream registers while we're 1292 * here. Only it cannot do the later because we're sitting on the big 1293 * HDA device lock, see assertions in hdaR3Timer(). So, this is an 1294 * pointless guesture given that we clear it again after the loop. */ 1295 HDA_STREAM_REG(pThis, STS, uSD) |= HDA_SDSTS_FIFORDY; 1296 1297 /* 1298 * 1299 * The DMA copy loop. 1300 * 1301 */ 1302 uint8_t abBounce[4096 + 128]; /* Most guest does at most 4KB BDLE. So, 4KB + space for a partial frame to reduce loops. */ 1303 uint32_t cbBounce = 0; /* in case of incomplete frames between buffer segments */ 1304 PRTCIRCBUF pCircBuf = pStreamR3->State.pCircBuf; 1305 uint32_t cbLeft = cbToConsume; 1306 Assert(cbLeft == pStreamShared->State.cbTransferSize); 1307 Assert(PDMAudioPropsIsSizeAligned(&pStreamShared->State.Cfg.Props, cbLeft)); 1308 1309 while (cbLeft > 0) 1310 { 1311 STAM_PROFILE_START(&pThis->StatIn, a); 1312 1313 /* 1314 * Figure out how much we can read & write in this iteration. 1315 */ 1316 uint32_t cbChunk = 0; 1317 RTGCPHYS GCPhys = hdaR3StreamDmaBufGet(pStreamShared, &cbChunk); 1318 1319 /* Need to diverge if the frame format differs or if we're writing silence. */ 1320 if ( !pStreamR3->State.Mapping.fMappingNeeded 1321 && !fWriteSilence) 1322 { 1323 if (cbChunk <= cbLeft) 1324 { /* very likely */ } 1325 else 1326 cbChunk = cbLeft; 1327 1328 /* 1329 * Write the host data directly into the guest buffers. 1330 */ 1331 while (cbChunk > 0) 1332 { 1333 /* Grab internal DMA buffer space and read into it. */ 1334 void /*const*/ *pvBufSrc; 1335 size_t cbBufSrc; 1336 RTCircBufAcquireReadBlock(pCircBuf, cbChunk, &pvBufSrc, &cbBufSrc); 1337 AssertBreakStmt(cbBufSrc, RTCircBufReleaseReadBlock(pCircBuf, 0)); 1338 1339 int rc2 = PDMDevHlpPCIPhysWrite(pDevIns, GCPhys, pvBufSrc, cbBufSrc); 1340 AssertRC(rc2); 1341 1342 #ifdef HDA_DEBUG_SILENCE 1343 fix me if relevant; 1370 1344 #endif 1371 1372 uint32_t cbProcessed = 0; 1373 uint32_t cbLeft = cbToProcess; 1374 1375 /* Whether an interrupt has been sent (asserted) for this transfer period already or not. 1376 * 1377 * Note: Windows 10 relies on this, e.g. sending more than one interrupt per transfer period 1378 * confuses the Windows' audio driver and will screw up the audio data. So only send 1379 * one interrupt per transfer period. 1380 */ 1381 bool fInterruptSent = false; 1382 1383 /* Set the FIFORDY bit on the stream while doing the transfer. */ 1384 HDA_STREAM_REG(pThis, STS, uSD) |= HDA_SDSTS_FIFORDY; 1385 1386 while (cbLeft) 1387 { 1388 /* Limit the chunk to the stream's FIFO size and what's left to process. */ 1389 uint32_t cbChunk = RT_MIN(cbLeft, pStreamShared->u8FIFOS); 1390 1391 /* Limit the chunk to the remaining data of the current BDLE. */ 1392 uint32_t cbDmaBuf = 0; 1393 RTGCPHYS GCPhys = hdaR3StreamDmaBufGet(pStreamShared, &cbDmaBuf); 1394 cbChunk = RT_MIN(cbChunk, cbDmaBuf); 1395 1396 if (!cbChunk) 1397 break; 1398 1399 STAM_PROFILE_START(&pThis->StatIn, a); 1400 1345 if (RT_LIKELY(!pStreamR3->Dbg.Runtime.fEnabled)) 1346 { /* likely */ } 1347 else 1348 DrvAudioHlpFileWrite(pStreamR3->Dbg.Runtime.pFileDMARaw, pvBufSrc, cbBufSrc, 0 /* fFlags */); 1349 1350 #ifdef VBOX_WITH_DTRACE 1351 VBOXDD_HDA_STREAM_DMA_IN((uint32_t)uSD, (uint32_t)cbBufSrc, pStreamR3->State.offRead); 1352 #endif 1353 pStreamR3->State.offRead += cbBufSrc; 1354 RTCircBufReleaseReadBlock(pCircBuf, cbBufSrc); 1355 STAM_COUNTER_ADD(&pThis->StatBytesRead, cbBufSrc); 1356 1357 /* advance */ 1358 cbChunk -= (uint32_t)cbBufSrc; 1359 GCPhys += cbBufSrc; 1360 cbLeft -= (uint32_t)cbBufSrc; 1361 pStreamShared->State.offCurBdle += (uint32_t)cbBufSrc; 1362 } 1363 } 1401 1364 /* 1402 * Copy out of the internal DMA buffer. 1403 * @todo eliminate extra copy. 1365 * Either we've got some initial silence to write, or we need to do 1366 * channel mapping. Both produces guest output into the bounce buffer, 1367 * which is then copied into guest memory. The bounce buffer may keep 1368 * partial frames there for the next BDLE, if an BDLE isn't frame aligned. 1369 * 1370 * Note! cbLeft is relative to the input (host) frame size. 1371 * cbChunk OTOH is relative to output (guest) size. 1404 1372 */ 1405 PRTCIRCBUF pCircBuf = pStreamR3->State.pCircBuf; 1406 uint8_t *pabFIFO = pStreamShared->abFIFO; 1407 uint32_t cbDMAWritten = 0; 1408 uint32_t cbDMAToWrite = cbChunk; 1409 1410 /** @todo Do we need interleaving streams support here as well? 1411 * Never saw anything else besides mono/stereo mics (yet). */ 1412 while (cbDMAToWrite) 1373 else 1413 1374 { 1414 void *pvBuf; size_t cbBuf; 1415 RTCircBufAcquireReadBlock(pCircBuf, cbDMAToWrite, &pvBuf, &cbBuf); 1416 1417 if ( !cbBuf 1418 && !RTCircBufUsed(pCircBuf)) 1419 break; 1420 1421 memcpy(pabFIFO + cbDMAWritten, pvBuf, cbBuf); 1375 Assert(PDMAudioPropsIsSizeAligned(&pStreamShared->State.Cfg.Props, cbLeft)); 1376 uint32_t const cbLeftGuest = PDMAudioPropsFramesToBytes(&pStreamR3->State.Mapping.GuestProps, 1377 PDMAudioPropsBytesToFrames(&pStreamShared->State.Cfg.Props, 1378 cbLeft)); 1379 if (cbChunk <= cbLeftGuest) 1380 { /* very likely */ } 1381 else 1382 cbChunk = cbLeftGuest; 1383 1384 /* 1385 * Work till we've covered the chunk. 1386 */ 1387 Log5Func(("loop0: GCPhys=%RGp cbChunk=%#x + cbBounce=%#x\n", GCPhys, cbChunk, cbBounce)); 1388 while (cbChunk > 0) 1389 { 1390 /* Figure out how much we need to convert into the bounce buffer: */ 1391 uint32_t cbGuest = PDMAudioPropsRoundUpBytesToFrame(&pStreamR3->State.Mapping.GuestProps, cbChunk - cbBounce); 1392 uint32_t cFrames = PDMAudioPropsBytesToFrames(&pStreamR3->State.Mapping.GuestProps, 1393 RT_MIN(cbGuest, sizeof(abBounce) - cbBounce)); 1394 size_t cbBufSrc; 1395 if (!fWriteSilence) 1396 { 1397 /** @todo we could loop here to optimize buffer wrap around. Not important now though. */ 1398 void /*const*/ *pvBufSrc; 1399 RTCircBufAcquireReadBlock(pCircBuf, PDMAudioPropsFramesToBytes(&pStreamShared->State.Cfg.Props, cFrames), 1400 &pvBufSrc, &cbBufSrc); 1401 1402 uint32_t const cFramesToConvert = PDMAudioPropsBytesToFrames(&pStreamShared->State.Cfg.Props, 1403 (uint32_t)cbBufSrc); 1404 Assert(PDMAudioPropsFramesToBytes(&pStreamShared->State.Cfg.Props, cFramesToConvert) == cbBufSrc); 1405 Assert(cFramesToConvert > 0); 1406 Assert(cFramesToConvert <= cFrames); 1407 1408 pStreamR3->State.Mapping.pfnHostToGuest(&abBounce[cbBounce], pvBufSrc, cFramesToConvert, 1409 &pStreamR3->State.Mapping); 1410 Log5Func((" loop1: cbBounce=%#05x cFramesToConvert=%#05x cbBufSrc=%#x%s\n", 1411 cbBounce, cFramesToConvert, cbBufSrc, ASMMemIsZero(pvBufSrc, cbBufSrc) ? " all zero" : "")); 1412 #ifdef HDA_DEBUG_SILENCE 1413 fix me if relevant; 1414 #endif 1415 if (RT_LIKELY(!pStreamR3->Dbg.Runtime.fEnabled)) 1416 { /* likely */ } 1417 else 1418 DrvAudioHlpFileWrite(pStreamR3->Dbg.Runtime.pFileDMARaw, pvBufSrc, cbBufSrc, 0 /* fFlags */); 1419 1422 1420 #ifdef VBOX_WITH_DTRACE 1423 VBOXDD_HDA_STREAM_DMA_IN((uint32_t)uSD, (uint32_t)cbBuf, pStreamR3->State.offRead);1421 VBOXDD_HDA_STREAM_DMA_IN((uint32_t)uSD, (uint32_t)cbBufSrc, pStreamR3->State.offRead); 1424 1422 #endif 1425 pStreamR3->State.offRead += cbBuf; 1426 1427 RTCircBufReleaseReadBlock(pCircBuf, cbBuf); 1428 1429 Assert(cbDMAToWrite >= cbBuf); 1430 cbDMAToWrite -= (uint32_t)cbBuf; 1431 cbDMAWritten += (uint32_t)cbBuf; 1432 Assert(cbDMAWritten <= cbChunk); 1423 1424 pStreamR3->State.offRead += cbBufSrc; 1425 RTCircBufReleaseReadBlock(pCircBuf, cbBufSrc); 1426 1427 cFrames = cFramesToConvert; 1428 cbGuest = cbBounce + PDMAudioPropsFramesToBytes(&pStreamR3->State.Mapping.GuestProps, cFrames); 1429 } 1430 else 1431 { 1432 cbBufSrc = PDMAudioPropsFramesToBytes(&pStreamShared->State.Cfg.Props, cFrames); 1433 cbGuest = PDMAudioPropsFramesToBytes(&pStreamR3->State.Mapping.GuestProps, cFrames); 1434 PDMAudioPropsClearBuffer(&pStreamR3->State.Mapping.GuestProps, 1435 &abBounce[cbBounce], cbGuest, cFrames); 1436 cbGuest += cbBounce; 1437 } 1438 1439 /* Write it to the guest buffer. */ 1440 uint32_t cbGuestActual = RT_MIN(cbGuest, cbChunk); 1441 int rc2 = PDMDevHlpPCIPhysWrite(pDevIns, GCPhys, abBounce, cbGuestActual); 1442 AssertRC(rc2); 1443 STAM_COUNTER_ADD(&pThis->StatBytesRead, cbGuestActual); 1444 1445 /* advance */ 1446 cbLeft -= (uint32_t)cbBufSrc; 1447 cbChunk -= cbGuestActual; 1448 GCPhys += cbGuestActual; 1449 pStreamShared->State.offCurBdle += cbGuestActual; 1450 1451 cbBounce = cbGuest - cbGuestActual; 1452 if (cbBounce) 1453 memmove(abBounce, &abBounce[cbGuestActual], cbBounce); 1454 1455 Log5Func((" loop1: GCPhys=%RGp cbGuestActual=%#x cbBounce=%#x cFrames=%#x\n", GCPhys, cbGuestActual, cbBounce, cFrames)); 1456 } 1457 Log5Func(("loop0: GCPhys=%RGp cbBounce=%#x cbLeft=%#x\n", GCPhys, cbBounce, cbLeft)); 1433 1458 } 1434 1459 1435 if (cbDMAToWrite) 1436 { 1437 LogRel2(("HDA: FIFO underflow for stream #%RU8 (%RU32 bytes outstanding)\n", uSD, cbDMAToWrite)); 1438 1439 Assert(cbChunk == cbDMAWritten + cbDMAToWrite); 1440 memset((uint8_t *)pabFIFO + cbDMAWritten, 0, cbDMAToWrite); 1441 cbDMAWritten = cbChunk; 1442 } 1460 STAM_PROFILE_STOP(&pThis->StatIn, a); 1443 1461 1444 1462 /* 1445 * Write to the guest.1463 * Is the buffer descriptor complete. 1446 1464 */ 1447 if (RT_LIKELY(!pStreamR3->Dbg.Runtime.fEnabled))1448 { /* likely */ }1449 else1450 DrvAudioHlpFileWrite(pStreamR3->Dbg.Runtime.pFileDMARaw, pabFIFO, cbDMAWritten, 0 /* fFlags */);1451 1452 rc = PDMDevHlpPCIPhysWrite(pDevIns, GCPhys, pabFIFO, cbDMAWritten);1453 AssertLogRelMsgRC(rc, ("HDA: Write at %RGp LB %#x -> %Rrc\n", GCPhys, cbDMAWritten, rc));1454 1455 STAM_COUNTER_ADD(&pThis->StatBytesWritten, cbChunk);1456 1457 STAM_PROFILE_STOP(&pThis->StatIn, a);1458 1459 /* Advance. */1460 pStreamShared->State.offCurBdle += cbDMAWritten;1461 Assert(cbLeft >= cbDMAWritten);1462 cbLeft -= cbDMAWritten;1463 cbProcessed += cbDMAWritten;1464 1465 1465 if (hdaR3StreamDmaBufIsComplete(pStreamShared)) 1466 1466 { 1467 Log3Func(("[SD%RU8] Completed BDLE%u %#RX64 LB %#RX32 fFlags=%#x (wrote %#x)\n",1467 Log3Func(("[SD%RU8] Completed BDLE%u %#RX64 LB %#RX32 fFlags=%#x\n", 1468 1468 uSD, pStreamShared->State.idxCurBdle, pStreamShared->State.aBdl[pStreamShared->State.idxCurBdle].GCPhys, 1469 1469 pStreamShared->State.aBdl[pStreamShared->State.idxCurBdle].cb, 1470 pStreamShared->State.aBdl[pStreamShared->State.idxCurBdle].fFlags , cbDMAWritten));1470 pStreamShared->State.aBdl[pStreamShared->State.idxCurBdle].fFlags)); 1471 1471 1472 1472 /* Make sure to also update the wall clock when a BDLE is complete. 1473 1473 * Needed for Windows 10 guests. */ 1474 /** @todo there is a rounding error here. */ 1474 1475 hdaR3WalClkSet(pThis, pThisCC, 1475 1476 hdaWalClkGetCurrent(pThis) 1476 + hdaR3StreamPeriodFramesToWalClk( pPeriod,1477 + hdaR3StreamPeriodFramesToWalClk(&pStreamShared->State.Period, 1477 1478 hdaR3StreamDmaBufGetSize(pStreamShared) 1478 1479 / pStreamR3->State.Mapping.cbGuestFrame), … … 1481 1482 /* 1482 1483 * Update the stream's current position. 1484 * 1483 1485 * Do this as accurate and close to the actual data transfer as possible. 1484 1486 * All guetsts rely on this, depending on the mechanism they use (LPIB register or DMA counters). … … 1492 1494 if (hdaR3StreamDmaBufNeedsIrq(pStreamShared)) 1493 1495 { 1494 /* If the IOCE ("Interrupt On Completion Enable") bit of the SDCTL register is set 1495 * we need to generate an interrupt. 1496 */ 1496 /* If the IOCE ("Interrupt On Completion Enable") bit of the SDCTL 1497 register is set we need to generate an interrupt. */ 1497 1498 if (HDA_STREAM_REG(pThis, CTL, uSD) & HDA_SDCTL_IOCE) 1498 1499 { 1499 1500 /* Assert the interrupt before actually fetching the next BDLE below. */ 1500 if (!fInterruptSent) 1501 { 1502 pStreamShared->State.cTransferPendingInterrupts = 1; 1503 Log3Func(("[SD%RU8] Scheduling interrupt\n", uSD)); 1504 1505 /* 1506 * Set the stream's BCIS bit. 1507 * 1508 * Note: This only must be done if the whole period is complete, and not if only 1509 * one specific BDL entry is complete (if it has the IOC bit set). 1510 * 1511 * This will otherwise confuses the guest when it 1) deasserts the interrupt, 1512 * 2) reads SDSTS (with BCIS set) and then 3) too early reads a (wrong) WALCLK value. 1513 * 1514 * snd_hda_intel on Linux will tell. 1515 */ 1516 HDA_STREAM_REG(pThis, STS, uSD) |= HDA_SDSTS_BCIS; 1517 1518 /* Trigger an interrupt first and let hdaRegWriteSDSTS() deal with 1519 * ending / beginning a period. */ 1520 HDA_PROCESS_INTERRUPT(pDevIns, pThis); 1521 1522 fInterruptSent = true; 1523 } 1501 pStreamShared->State.cTransferPendingInterrupts = 1; 1502 Log3Func(("[SD%RU8] Scheduling interrupt\n", uSD)); 1503 1504 /* Trigger an interrupt first and let hdaRegWriteSDSTS() deal with 1505 * ending / beginning of a period. */ 1506 /** @todo r=bird: What does the above comment mean? */ 1507 HDA_STREAM_REG(pThis, STS, uSD) |= HDA_SDSTS_BCIS; 1508 HDA_PROCESS_INTERRUPT(pDevIns, pThis); 1524 1509 } 1525 1510 } 1526 1511 1512 /* 1513 * Advance to the next BDLE. 1514 */ 1527 1515 hdaR3StreamDmaBufAdvanceToNext(pStreamShared); 1528 1516 } 1529 1517 else 1530 Log3Func(("[SD%RU8] Not completed BDLE%u %#RX64 LB %#RX32 fFlags=%#x: off=%#RX32 , wrote %#x\n",1518 Log3Func(("[SD%RU8] Not completed BDLE%u %#RX64 LB %#RX32 fFlags=%#x: off=%#RX32\n", 1531 1519 uSD, pStreamShared->State.idxCurBdle, pStreamShared->State.aBdl[pStreamShared->State.idxCurBdle].GCPhys, 1532 1520 pStreamShared->State.aBdl[pStreamShared->State.idxCurBdle].cb, 1533 pStreamShared->State.aBdl[pStreamShared->State.idxCurBdle].fFlags, pStreamShared->State.offCurBdle, cbDMAWritten)); 1534 } 1535 1536 /* Remove the FIFORDY bit again. */ 1521 pStreamShared->State.aBdl[pStreamShared->State.idxCurBdle].fFlags, pStreamShared->State.offCurBdle)); 1522 } 1523 1524 Assert(cbLeft == 0); /* There shall be no break statements in the above loop, so cbLeft is always zero here! */ 1525 AssertMsg(cbBounce == 0, ("%#x\n", cbBounce)); 1526 1527 /* 1528 * Clear the (pointless) FIFORDY bit again. 1529 */ 1537 1530 HDA_STREAM_REG(pThis, STS, uSD) &= ~HDA_SDSTS_FIFORDY; 1538 1531 1539 /* Sanity. */ 1540 Assert(cbProcessed == cbToProcess); 1541 Assert(cbLeft == 0); 1542 1543 hdaR3StreamPeriodInc(pPeriod, RT_MIN(cbProcessed / pStreamR3->State.Mapping.cbGuestFrame, 1544 hdaR3StreamPeriodGetRemainingFrames(pPeriod))); 1545 1546 const bool fTransferComplete = cbLeft == 0; 1547 if (fTransferComplete) 1548 { 1549 /* 1550 * Try updating the wall clock. 1551 * 1552 * Note 1) Only certain guests (like Linux' snd_hda_intel) rely on the WALCLK register 1553 * in order to determine the correct timing of the sound device. Other guests 1554 * like Windows 7 + 10 (or even more exotic ones like Haiku) will completely 1555 * ignore this. 1556 * 1557 * Note 2) When updating the WALCLK register too often / early (or even in a non-monotonic 1558 * fashion) this *will* upset guest device drivers and will completely fuck up the 1559 * sound output. Running VLC on the guest will tell! 1560 */ 1561 const bool fWalClkSet = hdaR3WalClkSet(pThis, pThisCC, 1562 RT_MIN( hdaWalClkGetCurrent(pThis) 1563 + hdaR3StreamPeriodFramesToWalClk(pPeriod, 1564 cbProcessed 1565 / pStreamR3->State.Mapping.cbGuestFrame), 1566 hdaR3WalClkGetMax(pThis, pThisCC)), 1567 false /* fForce */); 1568 RT_NOREF(fWalClkSet); 1569 } 1570 1571 /* Always update this timestamp, no matter what pStreamShared->State.tsTransferNext is. */ 1572 pStreamShared->State.tsTransferLast = tsNow; 1573 1574 Log3Func(("[SD%RU8] %#RX32/%#RX32 @ %#RX64\n", uSD, cbProcessed, pStreamShared->State.cbTransferSize, 1575 (hdaGetDirFromSD(uSD) == PDMAUDIODIR_OUT ? pStreamR3->State.offWrite : pStreamR3->State.offRead) - cbProcessed)); 1576 Log3Func(("[SD%RU8] fTransferComplete=%RTbool, cTransferPendingInterrupts=%RU8\n", 1577 uSD, fTransferComplete, pStreamShared->State.cTransferPendingInterrupts)); 1578 1579 LogFlowFuncLeave(); 1580 1581 hdaStreamUnlock(pStreamShared); 1582 1532 /* 1533 * Try updating the wall clock. 1534 * 1535 * Note 1) Only certain guests (like Linux' snd_hda_intel) rely on the WALCLK register 1536 * in order to determine the correct timing of the sound device. Other guests 1537 * like Windows 7 + 10 (or even more exotic ones like Haiku) will completely 1538 * ignore this. 1539 * 1540 * Note 2) When updating the WALCLK register too often / early (or even in a non-monotonic 1541 * fashion) this *will* upset guest device drivers and will completely fuck up the 1542 * sound output. Running VLC on the guest will tell! 1543 */ 1544 uint32_t const cFramesProcessed = PDMAudioPropsBytesToFrames(&pStreamShared->State.Cfg.Props, cbToConsume); 1545 /** @todo this needs to go, but we need it for hdaR3WalClkGetMax below. */ 1546 hdaR3StreamPeriodInc(&pStreamShared->State.Period, 1547 RT_MIN(cFramesProcessed, hdaR3StreamPeriodGetRemainingFrames(&pStreamShared->State.Period))); 1548 1549 uint64_t const cWallTicks = hdaR3StreamPeriodFramesToWalClk(&pStreamShared->State.Period, cFramesProcessed); 1550 uint64_t const uWallNew = hdaWalClkGetCurrent(pThis) + cWallTicks; 1551 uint64_t const uWallMax = hdaR3WalClkGetMax(pThis, pThisCC); 1552 bool const fWalClkSet = hdaR3WalClkSet(pThis, pThisCC, RT_MIN(uWallNew, uWallMax), false /* fForce */); 1553 RT_NOREF(fWalClkSet); 1554 1555 /* 1556 * Log and leave. 1557 */ 1558 Log3Func(("[SD%RU8] %#RX32/%#RX32 @ %#RX64 - cTransferPendingInterrupts=%RU8\n", 1559 uSD, cbToConsume, pStreamShared->State.cbTransferSize, pStreamR3->State.offRead - cbToConsume, 1560 pStreamShared->State.cTransferPendingInterrupts)); 1583 1561 return VINF_SUCCESS; 1584 1562 } 1585 1563 1564 1565 /** 1566 * Input streams: Pulls data from to the host device thru the mixer, putting it 1567 * in the internal DMA buffer. 1568 * 1569 * @param pStreamShared HDA stream to update (shared bits). 1570 * @param pStreamR3 HDA stream to update (ring-3 bits). 1571 * @param pSink The mixer sink to push to. 1572 */ 1573 static void hdaR3StreamPullFromMixer(PHDASTREAM pStreamShared, PHDASTREAMR3 pStreamR3, PAUDMIXSINK pSink) 1574 { 1575 int rc = AudioMixerSinkUpdate(pSink); 1576 AssertRC(rc); 1577 1578 /* Is the sink ready to be read (host input data) from? If so, by how much? */ 1579 uint32_t cbSinkReadable = AudioMixerSinkGetReadable(pSink); 1580 1581 /* How much (guest input) data is available for writing at the moment for the HDA stream? */ 1582 const uint32_t cbStreamFree = hdaR3StreamGetFree(pStreamR3); 1583 1584 Log3Func(("[SD%RU8] cbSinkReadable=%RU32, cbStreamFree=%RU32\n", pStreamShared->u8SD, cbSinkReadable, cbStreamFree)); 1585 1586 /* Do not read more than the HDA stream can hold at the moment. 1587 * The host sets the overall pace. */ 1588 if (cbSinkReadable > cbStreamFree) 1589 cbSinkReadable = cbStreamFree; 1590 1591 /** @todo should we throttle (read less) this if we're far ahead? */ 1592 1593 /* 1594 * Copy loop. 1595 */ 1596 while (cbSinkReadable) 1597 { 1598 /* Read a chunk of data. */ 1599 uint8_t abBuf[4096]; 1600 uint32_t cbRead = 0; 1601 rc = AudioMixerSinkRead(pSink, AUDMIXOP_COPY, abBuf, RT_MIN(cbSinkReadable, sizeof(abBuf)), &cbRead); 1602 AssertRCBreak(rc); 1603 AssertMsg(cbRead > 0, ("Nothing read from sink, even if %RU32 bytes were (still) announced\n", cbSinkReadable)); 1604 1605 /* Write it to the internal DMA buffer. */ 1606 uint32_t off = 0; 1607 while (off < cbRead) 1608 { 1609 void *pvDstBuf; 1610 size_t cbDstBuf; 1611 RTCircBufAcquireWriteBlock(pStreamR3->State.pCircBuf, cbRead - off, &pvDstBuf, &cbDstBuf); 1612 1613 memcpy(pvDstBuf, &abBuf[off], cbDstBuf); 1614 1615 #ifdef VBOX_WITH_DTRACE 1616 VBOXDD_HDA_STREAM_AIO_IN((uint32_t)pStreamR3->u8SD, (uint32_t)cbDstBuf, pStreamR3->State.offWrite); 1617 #endif 1618 pStreamR3->State.offWrite += cbDstBuf; 1619 1620 RTCircBufReleaseWriteBlock(pStreamR3->State.pCircBuf, cbDstBuf); 1621 1622 off += cbDstBuf; 1623 } 1624 Assert(off == cbRead); 1625 1626 /* Write to debug file? */ 1627 if (RT_LIKELY(!pStreamR3->Dbg.Runtime.fEnabled)) 1628 { /* likely */ } 1629 else 1630 DrvAudioHlpFileWrite(pStreamR3->Dbg.Runtime.pFileStream, abBuf, cbRead, 0 /* fFlags */); 1631 1632 /* Advance. */ 1633 Assert(cbRead <= cbSinkReadable); 1634 cbSinkReadable -= cbRead; 1635 } 1636 } 1586 1637 1587 1638 /** … … 1608 1659 PHDASTREAMR3 pStreamR3, uint32_t cbToProduce, uint64_t tsNowNs) 1609 1660 { 1610 PHDASTREAMPERIOD const pPeriod = &pStreamShared->State.Period; 1611 uint8_t const uSD = pStreamShared->u8SD; 1661 uint8_t const uSD = pStreamShared->u8SD; 1612 1662 LogFlowFunc(("ENTER - #%u cbToProduce=%#x\n", uSD, cbToProduce)); 1613 1663 … … 1714 1764 AssertRC(rc2); 1715 1765 1716 # 1766 #ifdef HDA_DEBUG_SILENCE 1717 1767 fix me if relevant; 1718 # 1768 #endif 1719 1769 if (RT_LIKELY(!pStreamR3->Dbg.Runtime.fEnabled)) 1720 1770 { /* likely */ } … … 1722 1772 DrvAudioHlpFileWrite(pStreamR3->Dbg.Runtime.pFileDMARaw, pvBufDst, cbBufDst, 0 /* fFlags */); 1723 1773 1774 #ifdef VBOX_WITH_DTRACE 1775 VBOXDD_HDA_STREAM_DMA_OUT((uint32_t)uSD, (uint32_t)cbBufDst, pStreamR3->State.offWrite); 1776 #endif 1724 1777 pStreamR3->State.offWrite += cbBufDst; 1725 1778 RTCircBufReleaseWriteBlock(pCircBuf, cbBufDst); … … 1744 1797 { 1745 1798 Assert(PDMAudioPropsIsSizeAligned(&pStreamShared->State.Cfg.Props, cbLeft)); 1746 uint32_t const cbLeft Input = PDMAudioPropsFramesToBytes(&pStreamR3->State.Mapping.GuestProps,1799 uint32_t const cbLeftGuest = PDMAudioPropsFramesToBytes(&pStreamR3->State.Mapping.GuestProps, 1747 1800 PDMAudioPropsBytesToFrames(&pStreamShared->State.Cfg.Props, 1748 1801 cbLeft)); 1749 if (cbChunk <= cbLeft Input)1802 if (cbChunk <= cbLeftGuest) 1750 1803 { /* very likely */ } 1751 1804 else 1752 cbChunk = cbLeft Input;1805 cbChunk = cbLeftGuest; 1753 1806 1754 1807 /* … … 1836 1889 hdaR3WalClkSet(pThis, pThisCC, 1837 1890 hdaWalClkGetCurrent(pThis) 1838 + hdaR3StreamPeriodFramesToWalClk( pPeriod,1891 + hdaR3StreamPeriodFramesToWalClk(&pStreamShared->State.Period, 1839 1892 hdaR3StreamDmaBufGetSize(pStreamShared) 1840 1893 / pStreamR3->State.Mapping.cbGuestFrame), … … 1908 1961 RT_MIN(cFramesProcessed, hdaR3StreamPeriodGetRemainingFrames(&pStreamShared->State.Period))); 1909 1962 1910 uint64_t const cWallTicks = hdaR3StreamPeriodFramesToWalClk( pPeriod, cFramesProcessed);1963 uint64_t const cWallTicks = hdaR3StreamPeriodFramesToWalClk(&pStreamShared->State.Period, cFramesProcessed); 1911 1964 uint64_t const uWallNew = hdaWalClkGetCurrent(pThis) + cWallTicks; 1912 1965 uint64_t const uWallMax = hdaR3WalClkGetMax(pThis, pThisCC); … … 2212 2265 else 2213 2266 { 2214 /** @todo Re-org this. Like in the output case, the timer thread should try do 2215 * AIO work if we have an underrun. */ 2267 Assert(hdaGetDirFromSD(pStreamShared->u8SD) == PDMAUDIODIR_IN); 2268 2269 /* 2270 * If we're the async I/O worker, or not using AIO, pull bytes 2271 * from the mixer and into our internal DMA buffer. 2272 */ 2216 2273 # ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO 2217 2274 if (!fInTimer) 2218 2275 # endif 2219 { 2220 rc2 = AudioMixerSinkUpdate(pSink); 2221 AssertRC(rc2); 2222 2223 /* Is the sink ready to be read (host input data) from? If so, by how much? */ 2224 uint32_t cbSinkReadable = AudioMixerSinkGetReadable(pSink); 2225 2226 /* How much (guest input) data is available for writing at the moment for the HDA stream? */ 2227 const uint32_t cbStreamFree = hdaR3StreamGetFree(pStreamR3); 2228 2229 Log3Func(("[SD%RU8] cbSinkReadable=%RU32, cbStreamFree=%RU32\n", pStreamShared->u8SD, cbSinkReadable, cbStreamFree)); 2230 2231 /* Do not read more than the HDA stream can hold at the moment. 2232 * The host sets the overall pace. */ 2233 if (cbSinkReadable > cbStreamFree) 2234 cbSinkReadable = cbStreamFree; 2235 2236 if (cbSinkReadable) 2237 { 2238 void *pvFIFO = &pStreamShared->abFIFO[0]; 2239 uint32_t cbFIFO = (uint32_t)sizeof(pStreamShared->abFIFO); 2240 2241 while (cbSinkReadable) 2242 { 2243 uint32_t cbRead; 2244 rc2 = AudioMixerSinkRead(pSink, AUDMIXOP_COPY, 2245 pvFIFO, RT_MIN(cbSinkReadable, cbFIFO), &cbRead); 2246 AssertRCBreak(rc2); 2247 2248 if (!cbRead) 2249 { 2250 AssertMsgFailed(("Nothing read from sink, even if %RU32 bytes were (still) announced\n", cbSinkReadable)); 2251 break; 2252 } 2253 2254 /* Write (guest input) data to the stream which was read from stream's sink before. */ 2255 uint32_t cbWritten; 2256 rc2 = hdaR3StreamWrite(pStreamR3, pvFIFO, cbRead, &cbWritten); 2257 AssertRCBreak(rc2); 2258 AssertBreak(cbWritten > 0); /* Should never happen, as we know how much we can write. */ 2259 2260 Assert(cbSinkReadable >= cbRead); 2261 cbSinkReadable -= cbRead; 2262 } 2263 } 2264 } 2276 hdaR3StreamPullFromMixer(pStreamShared, pStreamR3, pSink); 2265 2277 # ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO 2266 2278 else /* fInTimer */ 2267 2279 # endif 2268 2280 { 2281 /* 2282 * See how much data we've got buffered... 2283 */ 2284 bool fWriteSilence = false; 2285 uint32_t cbStreamUsed = hdaR3StreamGetUsed(pStreamR3); 2286 if (pStreamShared->State.fInputPreBuffered && cbStreamUsed >= cbPeriod) 2287 { /*likely*/ } 2288 /* Because it may take a while for the input stream to get going (at 2289 least with pulseaudio), we feed the guest silence till we've 2290 pre-buffer a reasonable amount of audio. */ 2291 else if (!pStreamShared->State.fInputPreBuffered) 2292 { 2293 if (cbStreamUsed < pStreamShared->State.cbInputPreBuffer) 2294 { 2295 Log3(("hdaR3StreamUpdate: Pre-buffering (got %#x out of %#x bytes)...\n", 2296 cbStreamUsed, pStreamShared->State.cbInputPreBuffer)); 2297 fWriteSilence = true; 2298 } 2299 else 2300 { 2301 Log3(("hdaR3StreamUpdate: Completed pre-buffering (got %#x, needed %#x bytes).\n", 2302 cbStreamUsed, pStreamShared->State.cbInputPreBuffer)); 2303 pStreamShared->State.fInputPreBuffered = true; 2304 fWriteSilence = true; /* For now, just do the most conservative thing. */ 2305 } 2306 cbStreamUsed = cbPeriod; 2307 } 2308 /* 2309 * When we're low on data, we must really try fetch some ourselves 2310 * as buffer underruns must not happen. 2311 */ 2312 else 2313 { 2314 STAM_REL_COUNTER_INC(&pStreamR3->State.StatDmaFlowProblems); 2315 Log(("hdaR3StreamUpdate: Warning! Stream #%u has insufficient data available: %u bytes, need %u. Will try move pull more data into the buffer...\n", 2316 pStreamShared->u8SD, cbStreamUsed, cbPeriod)); 2269 2317 # ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO 2270 if ( tsNowNs - pStreamShared->State.tsLastReadNs >= pStreamShared->State.Cfg.Device.cMsSchedulingHint * RT_NS_1MS 2271 || hdaR3StreamGetUsed(pStreamR3) < RT_MAX(cbPeriod, pStreamShared->State.cbAvgTransfer)) 2272 { 2273 Log5Func(("Notifying AIO thread\n")); 2274 rc2 = hdaR3StreamAsyncIONotify(pStreamR3); 2275 AssertRC(rc2); 2276 2277 pStreamShared->State.tsLastReadNs = tsNowNs; 2318 int rc = RTCritSectTryEnter(&pStreamR3->State.AIO.CritSect); 2319 if (RT_SUCCESS(rc)) 2320 { 2321 hdaR3StreamPullFromMixer(pStreamShared, pStreamR3, pSink); 2322 RTCritSectLeave(&pStreamR3->State.AIO.CritSect); 2323 } 2324 else 2325 RTThreadYield(); 2326 #else 2327 hdaR3StreamPullFromMixer(pStreamShared, pStreamR3, pSink); 2328 #endif 2329 Log(("hdaR3StreamUpdate: Gained %u bytes.\n", hdaR3StreamGetUsed(pStreamR3) - cbStreamUsed)); 2330 cbStreamUsed = hdaR3StreamGetUsed(pStreamR3); 2331 if (cbStreamUsed < cbPeriod) 2332 { 2333 /* Unable to find sufficient input data by simple prodding. 2334 In order to keep a constant byte stream following thru the DMA 2335 engine into the guest, we will try again and then fall back on 2336 filling the gap with silence. */ 2337 uint32_t cbSilence = 0; 2338 do 2339 { 2340 #ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO 2341 RTCritSectEnter(&pStreamR3->State.AIO.CritSect); 2342 #endif 2343 cbStreamUsed = hdaR3StreamGetUsed(pStreamR3); 2344 if (cbStreamUsed < cbPeriod) 2345 { 2346 hdaR3StreamPullFromMixer(pStreamShared, pStreamR3, pSink); 2347 cbStreamUsed = hdaR3StreamGetUsed(pStreamR3); 2348 while (cbStreamUsed < cbPeriod) 2349 { 2350 void *pvDstBuf; 2351 size_t cbDstBuf; 2352 RTCircBufAcquireWriteBlock(pStreamR3->State.pCircBuf, cbPeriod - cbStreamUsed, 2353 &pvDstBuf, &cbDstBuf); 2354 RT_BZERO(pvDstBuf, cbDstBuf); 2355 RTCircBufReleaseWriteBlock(pStreamR3->State.pCircBuf, cbDstBuf); 2356 cbSilence += cbDstBuf; 2357 cbStreamUsed += cbDstBuf; 2358 } 2359 } 2360 2361 #ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO 2362 RTCritSectLeave(&pStreamR3->State.AIO.CritSect); 2363 #endif 2364 } while (cbStreamUsed < cbPeriod); 2365 if (cbSilence > 0) 2366 { 2367 STAM_REL_COUNTER_INC(&pStreamR3->State.StatDmaFlowErrors); 2368 STAM_REL_COUNTER_ADD(&pStreamR3->State.StatDmaFlowErrorBytes, cbSilence); 2369 LogRel2(("HDA: Warning: Stream #%RU8 underrun, added %u bytes of silence (%u us)\n", pStreamShared->u8SD, 2370 cbSilence, PDMAudioPropsBytesToMicro(&pStreamR3->State.Mapping.GuestProps, cbSilence))); 2371 } 2372 } 2278 2373 } 2279 # endif 2280 const uint32_t cbStreamUsed = hdaR3StreamGetUsed(pStreamR3); 2374 2375 /* 2376 * Do the DMA'ing. 2377 */ 2281 2378 if (cbStreamUsed) 2282 2379 { 2283 rc2 = hdaR3StreamDoDmaInput(pDevIns, pThis, pThisCC, pStreamShared, pStreamR3, RT_MIN(cbStreamUsed, cbPeriod)); 2380 # ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO 2381 rc2 = PDMDevHlpCritSectEnter(pDevIns, &pStreamShared->CritSect, VERR_IGNORED); 2284 2382 AssertRC(rc2); 2383 # endif 2384 2385 rc2 = hdaR3StreamDoDmaInput(pDevIns, pThis, pThisCC, pStreamShared, pStreamR3, 2386 RT_MIN(cbStreamUsed, cbPeriod), fWriteSilence, tsNowNs); 2387 AssertRC(rc2); 2388 2389 # ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO 2390 rc2 = PDMDevHlpCritSectLeave(pDevIns, &pStreamShared->CritSect); 2391 AssertRC(rc2); 2392 # endif 2285 2393 } 2394 2395 # ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO 2396 /* 2397 * We should always kick the AIO thread. 2398 */ 2399 /** @todo This isn't entirely ideal. If we get into an underrun situation, 2400 * we ideally want the AIO thread to run right before the DMA timer 2401 * rather than right after it ran. */ 2402 Log5Func(("Notifying AIO thread\n")); 2403 rc2 = hdaR3StreamAsyncIONotify(pStreamR3); 2404 AssertRC(rc2); 2405 pStreamShared->State.tsLastReadNs = tsNowNs; 2406 # endif 2286 2407 } 2287 2408 } … … 2671 2792 * @param pStreamR3 HDA stream to notify async I/O thread for. 2672 2793 */ 2673 staticint hdaR3StreamAsyncIONotify(PHDASTREAMR3 pStreamR3)2794 int hdaR3StreamAsyncIONotify(PHDASTREAMR3 pStreamR3) 2674 2795 { 2675 2796 return RTSemEventSignal(pStreamR3->State.AIO.hEvent); -
trunk/src/VBox/Devices/Audio/HDAStream.h
r88137 r88158 125 125 uint8_t cTransferPendingInterrupts; 126 126 /** Unused, padding. */ 127 uint8_t abPadding1[3]; 127 uint8_t abPadding1[2]; 128 /** Input streams only: Set when we switch from feeding the guest silence and 129 * commits to proving actual audio input bytes. */ 130 bool fInputPreBuffered; 131 /** Input streams only: The number of bytes we need to prebuffer. */ 132 uint32_t cbInputPreBuffer; 133 uint32_t u32Padding2; 128 134 /** Timestamp (absolute, in timer ticks) of the last DMA data transfer. */ 129 135 uint64_t tsTransferLast; … … 156 162 /** The start time for the playback (on the timer clock). */ 157 163 uint64_t tsStart; 164 165 uint64_t au64Padding[3]; 158 166 159 167 /** @name DMA engine … … 307 315 /** Counter for unresovled under/overflows problems. */ 308 316 STAMCOUNTER StatDmaFlowErrors; 317 /** Number of bytes involved in unresolved flow errors. */ 318 STAMCOUNTER StatDmaFlowErrorBytes; 309 319 } State; 310 320 /** Debug bits. */ … … 357 367 void hdaR3StreamAsyncIOUnlock(PHDASTREAMR3 pStreamR3); 358 368 void hdaR3StreamAsyncIOEnable(PHDASTREAMR3 pStreamR3, bool fEnable); 369 int hdaR3StreamAsyncIONotify(PHDASTREAMR3 pStreamR3); 359 370 # endif /* VBOX_WITH_AUDIO_HDA_ASYNC_IO */ 360 371 /** @} */
Note:
See TracChangeset
for help on using the changeset viewer.