Changeset 89694 in vbox
- Timestamp:
- Jun 15, 2021 8:44:33 AM (4 years ago)
- svn:sync-xref-src-repo-rev:
- 145142
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Audio/DevIchAc97.cpp
r89693 r89694 36 36 # include <iprt/string.h> 37 37 # include <iprt/uuid.h> 38 # include <iprt/zero.h> 38 39 #endif 39 40 … … 378 379 /** Set if we've registered the asynchronous update job. */ 379 380 bool fRegisteredAsyncUpdateJob; 380 uint8_t Padding3; 381 /** Input streams only: Set when we switch from feeding the guest silence and 382 * commits to proving actual audio input bytes. */ 383 bool fInputPreBuffered; 381 384 /** (Virtual) clock ticks per transfer. */ 382 385 uint64_t cTransferTicks; … … 685 688 static uint32_t ichac97R3StreamGetFree(PAC97STREAMR3 pStreamCC); 686 689 static int ichac97R3StreamTransfer(PPDMDEVINS pDevIns, PAC97STATE pThis, PAC97STREAM pStream, 687 PAC97STREAMR3 pStreamCC, uint32_t cbToProcessMax );690 PAC97STREAMR3 pStreamCC, uint32_t cbToProcessMax, bool fWriteSilence); 688 691 static DECLCALLBACK(void) ichac97R3StreamUpdateAsyncIoJob(PPDMDEVINS pDevIns, PAUDMIXSINK pSink, void *pvUser); 689 692 … … 1024 1027 if (fEnable) 1025 1028 { 1029 /* Reset some of the state. */ 1030 pStreamCC->State.fInputPreBuffered = false; 1026 1031 if (pStreamCC->State.pCircBuf) 1027 1032 RTCircBufReset(pStreamCC->State.pCircBuf); 1028 1033 1034 /* (Re-)Open the steram if necessary. */ 1029 1035 rc = ichac97R3StreamOpen(pDevIns, pThis, pThisCC, pStream, pStreamCC, false /* fForce */); 1030 1036 … … 1371 1377 LogRel2(("AC97: Warning: Hit stream #%RU8 overflow, dropping %u bytes of audio data\n", 1372 1378 pStreamCC->u8SD, ichac97R3StreamGetUsed(pStreamCC))); 1373 # ifdef HDA_STRICT1379 # ifdef AC97_STRICT 1374 1380 AssertMsgFailed(("Hit stream #%RU8 overflow -- timing bug?\n", pStreamCC->u8SD)); 1375 1381 # endif … … 1392 1398 cbPeriod, PDMAudioPropsBytesToMilli(&pStreamCC->State.Cfg.Props, cbPeriod))); 1393 1399 1394 rc2 = ichac97R3StreamTransfer(pDevIns, pThis, pStream, pStreamCC, RT_MIN(cbStreamFree, cbPeriod) );1400 rc2 = ichac97R3StreamTransfer(pDevIns, pThis, pStream, pStreamCC, RT_MIN(cbStreamFree, cbPeriod), false /*fWriteSilence*/); 1395 1401 AssertRC(rc2); 1396 1402 … … 1404 1410 AssertRC(rc2); 1405 1411 } 1406 else /* Input (SDI). */ 1407 { 1408 #if 0 /* bird: I just love when crusial code like this with no explanation. This just causing AIO 1409 * skipping a DMA timer cycle if the timer callback is a bit quicker than the 'hint' (see HDA/9890). */ 1410 const uint64_t tsNowNs = RTTimeNanoTS(); 1411 if (tsNowNs - pStreamCC->State.tsLastUpdateNs >= pStreamCC->State.Cfg.Device.cMsSchedulingHint * RT_NS_1MS) 1412 /* 1413 * Input stream (SDI). 1414 */ 1415 else 1416 { 1417 /* 1418 * See how much data we've got buffered... 1419 */ 1420 bool fWriteSilence = false; 1421 uint32_t cbStreamUsed = ichac97R3StreamGetUsed(pStreamCC); 1422 if (pStreamCC->State.fInputPreBuffered && cbStreamUsed >= cbPeriod) 1423 { /*likely*/ } 1424 /* 1425 * Because it may take a while for the input stream to get going (at least 1426 * with pulseaudio), we feed the guest silence till we've pre-buffer a 1427 * couple of timer Hz periods. (This avoid lots of bogus buffer underruns 1428 * when starting an input stream and hogging the timer EMT.) 1429 */ 1430 else if (!pStreamCC->State.fInputPreBuffered) 1412 1431 { 1413 rc2 = AudioMixerSinkSignalUpdateJob(pSink); 1414 AssertRC(rc2); 1415 1416 pStreamCC->State.tsLastUpdateNs = tsNowNs; 1432 uint32_t const cbPreBuffer = PDMAudioPropsNanoToBytes(&pStreamCC->State.Cfg.Props, 1433 RT_NS_1SEC / pStreamCC->State.uTimerHz); 1434 if (cbStreamUsed < cbPreBuffer) 1435 { 1436 Log3(("hdaR3StreamUpdateDma: Pre-buffering (got %#x out of %#x bytes)...\n", cbStreamUsed, cbPreBuffer)); 1437 fWriteSilence = true; 1438 cbStreamUsed = cbPeriod; 1439 } 1440 else 1441 { 1442 Log3(("hdaR3StreamUpdateDma: Completed pre-buffering (got %#x, needed %#x bytes).\n", cbStreamUsed, cbPreBuffer)); 1443 pStreamCC->State.fInputPreBuffered = true; 1444 fWriteSilence = ichac97R3StreamGetFree(pStreamCC) >= cbPreBuffer + cbPreBuffer / 2; 1445 if (fWriteSilence) 1446 cbStreamUsed = cbPeriod; 1447 } 1417 1448 } 1418 #endif 1419 1420 uint32_t cbStreamUsed = ichac97R3StreamGetUsed(pStreamCC); 1421 if (cbStreamUsed) 1422 { /* likey */ } 1449 /* 1450 * When we're low on data, we must really try fetch some ourselves 1451 * as buffer underruns must not happen. 1452 */ 1423 1453 else 1424 1454 { 1425 /** @todo Record this as a statistic. Try pull some data into the DMA buffer.*/ 1455 STAM_REL_COUNTER_INC(&pStreamCC->State.StatDmaFlowProblems); 1456 Log(("ichac97R3StreamUpdateDma: Warning! Stream #%u has insufficient data available: %u bytes, need %u. Will try move pull more data into the buffer...\n", 1457 pStreamCC->u8SD, cbStreamUsed, cbPeriod)); 1458 int rc = AudioMixerSinkTryLock(pSink); 1459 if (RT_SUCCESS(rc)) 1460 { 1461 AudioMixerSinkUpdate(pSink, cbStreamUsed, cbPeriod); 1462 ichac97R3StreamPullFromMixer(pStreamCC, pSink); 1463 AudioMixerSinkUnlock(pSink); 1464 } 1465 else 1466 RTThreadYield(); 1467 Log(("ichac97R3StreamUpdateDma: Gained %u bytes.\n", ichac97R3StreamGetUsed(pStreamCC) - cbStreamUsed)); 1468 cbStreamUsed = ichac97R3StreamGetUsed(pStreamCC); 1469 if (cbStreamUsed < cbPeriod) 1470 { 1471 /* Unable to find sufficient input data by simple prodding. 1472 In order to keep a constant byte stream following thru the DMA 1473 engine into the guest, we will try again and then fall back on 1474 filling the gap with silence. */ 1475 uint32_t cbSilence = 0; 1476 do 1477 { 1478 AudioMixerSinkLock(pSink); 1479 1480 cbStreamUsed = ichac97R3StreamGetUsed(pStreamCC); 1481 if (cbStreamUsed < cbPeriod) 1482 { 1483 ichac97R3StreamPullFromMixer(pStreamCC, pSink); 1484 cbStreamUsed = ichac97R3StreamGetUsed(pStreamCC); 1485 while (cbStreamUsed < cbPeriod) 1486 { 1487 void *pvDstBuf; 1488 size_t cbDstBuf; 1489 RTCircBufAcquireWriteBlock(pStreamCC->State.pCircBuf, cbPeriod - cbStreamUsed, 1490 &pvDstBuf, &cbDstBuf); 1491 RT_BZERO(pvDstBuf, cbDstBuf); 1492 RTCircBufReleaseWriteBlock(pStreamCC->State.pCircBuf, cbDstBuf); 1493 cbSilence += (uint32_t)cbDstBuf; 1494 cbStreamUsed += (uint32_t)cbDstBuf; 1495 } 1496 } 1497 1498 AudioMixerSinkUnlock(pSink); 1499 } while (cbStreamUsed < cbPeriod); 1500 if (cbSilence > 0) 1501 { 1502 STAM_REL_COUNTER_INC(&pStreamCC->State.StatDmaFlowErrors); 1503 STAM_REL_COUNTER_ADD(&pStreamCC->State.StatDmaFlowErrorBytes, cbSilence); 1504 LogRel2(("AC97: Warning: Stream #%RU8 underrun, added %u bytes of silence (%u us)\n", pStreamCC->u8SD, 1505 cbSilence, PDMAudioPropsBytesToMicro(&pStreamCC->State.Cfg.Props, cbSilence))); 1506 } 1507 } 1426 1508 } 1427 1509 1510 /* 1511 * Do the DMA'ing. 1512 */ 1428 1513 if (cbStreamUsed) 1429 1514 { 1430 /* When running synchronously, do the DMA data transfers here. 1431 * Otherwise this will be done in the stream's async I/O thread. */ 1432 rc2 = ichac97R3StreamTransfer(pDevIns, pThis, pStream, pStreamCC, cbStreamUsed); 1515 rc2 = ichac97R3StreamTransfer(pDevIns, pThis, pStream, pStreamCC, RT_MIN(cbPeriod, cbStreamUsed), fWriteSilence); 1433 1516 AssertRC(rc2); 1517 1518 pStreamCC->State.tsLastUpdateNs = RTTimeNanoTS(); 1434 1519 } 1435 1520 … … 1443 1528 rc2 = AudioMixerSinkSignalUpdateJob(pSink); 1444 1529 AssertRC(rc2); 1445 pStreamCC->State.tsLastUpdateNs = RTTimeNanoTS();1446 1530 } 1447 1531 } … … 2631 2715 * @param pStreamCC The AC'97 stream to update (ring-3). 2632 2716 * @param cbToProcessMax Maximum of data (in bytes) to process. 2717 * @param fWriteSilence Whether to write silence if this is an input 2718 * stream (done while waiting for backend to get 2719 * going). 2633 2720 */ 2634 2721 static int ichac97R3StreamTransfer(PPDMDEVINS pDevIns, PAC97STATE pThis, PAC97STREAM pStream, 2635 PAC97STREAMR3 pStreamCC, uint32_t cbToProcessMax )2722 PAC97STREAMR3 pStreamCC, uint32_t cbToProcessMax, bool fWriteSilence) 2636 2723 { 2637 2724 if (!cbToProcessMax) … … 2714 2801 case AC97SOUNDSOURCE_PO_INDEX: /* Output */ 2715 2802 { 2716 void *pvDst; 2717 size_t cbDst; 2718 2803 void *pvDst = NULL; 2804 size_t cbDst = NULL; 2719 2805 RTCircBufAcquireWriteBlock(pCircBuf, cbChunk, &pvDst, &cbDst); 2720 2806 2721 2807 if (cbDst) 2722 2808 { 2723 int rc2 = PDMDevHlpPCIPhysRead(pDevIns, pRegs->bd.addr, (uint8_t *)pvDst, cbDst);2809 int rc2 = PDMDevHlpPCIPhysRead(pDevIns, pRegs->bd.addr, pvDst, cbDst); 2724 2810 AssertRC(rc2); 2725 2811 … … 2738 2824 case AC97SOUNDSOURCE_PI_INDEX: /* Input */ 2739 2825 case AC97SOUNDSOURCE_MC_INDEX: /* Input */ 2740 { 2741 void *pvSrc; 2742 size_t cbSrc; 2743 2744 RTCircBufAcquireReadBlock(pCircBuf, cbChunk, &pvSrc, &cbSrc); 2745 2746 if (cbSrc) 2826 if (!fWriteSilence) 2747 2827 { 2748 int rc2 = PDMDevHlpPCIPhysWrite(pDevIns, pRegs->bd.addr, (uint8_t *)pvSrc, cbSrc); 2828 void *pvSrc = NULL; 2829 size_t cbSrc = NULL; 2830 RTCircBufAcquireReadBlock(pCircBuf, cbChunk, &pvSrc, &cbSrc); 2831 2832 if (cbSrc) 2833 { 2834 int rc2 = PDMDevHlpPCIPhysWrite(pDevIns, pRegs->bd.addr, pvSrc, cbSrc); 2835 AssertRC(rc2); 2836 2837 if (RT_LIKELY(!pStreamCC->Dbg.Runtime.fEnabled)) 2838 { /* likely */ } 2839 else 2840 AudioHlpFileWrite(pStreamCC->Dbg.Runtime.pFileDMA, pvSrc, cbSrc, 0 /* fFlags */); 2841 } 2842 2843 RTCircBufReleaseReadBlock(pCircBuf, cbSrc); 2844 2845 cbChunk = (uint32_t)cbSrc; /* Update the current chunk size to what really has been read. */ 2846 } 2847 else 2848 { 2849 /* Since the format is signed 16-bit or 32-bit integer samples, we can 2850 use g_abRTZero64K as source and avoid some unnecessary bzero() work. */ 2851 cbChunk = RT_MIN(cbChunk, sizeof(g_abRTZero64K)); 2852 cbChunk = PDMAudioPropsFloorBytesToFrame(&pStreamCC->State.Cfg.Props, cbChunk); 2853 2854 int rc2 = PDMDevHlpPCIPhysWrite(pDevIns, pRegs->bd.addr, g_abRTZero64K, cbChunk); 2749 2855 AssertRC(rc2); 2750 2751 if (RT_LIKELY(!pStreamCC->Dbg.Runtime.fEnabled))2752 { /* likely */ }2753 else2754 AudioHlpFileWrite(pStreamCC->Dbg.Runtime.pFileDMA, pvSrc, cbSrc, 0 /* fFlags */);2755 2856 } 2756 2757 RTCircBufReleaseReadBlock(pCircBuf, cbSrc);2758 2759 cbChunk = (uint32_t)cbSrc; /* Update the current chunk size to what really has been read. */2760 2857 break; 2761 }2762 2858 2763 2859 default: … … 2772 2868 if (cbChunk) 2773 2869 { 2870 Assert(PDMAudioPropsIsSizeAligned(&pStreamCC->State.Cfg.Props, cbChunk)); 2871 Assert(cbChunk <= cbLeft); 2872 2774 2873 cbProcessedTotal += cbChunk; 2775 2874 Assert(cbProcessedTotal <= cbToProcessMax); 2776 Assert(cbLeft >= cbChunk); 2777 cbLeft -= cbChunk; 2778 Assert((cbChunk & 1) == 0); /* Else the following shift won't work */ 2779 2780 pRegs->picb -= (cbChunk >> 1); /** @todo r=andy Assumes 16bit samples. */ 2781 pRegs->bd.addr += cbChunk; 2875 cbLeft -= cbChunk; 2876 pRegs->picb -= (cbChunk >> 1); /** @todo r=andy Assumes 16bit samples. */ 2877 pRegs->bd.addr += cbChunk; 2782 2878 } 2783 2879
Note:
See TracChangeset
for help on using the changeset viewer.