VirtualBox

Changeset 88158 in vbox for trunk/src/VBox


Ignore:
Timestamp:
Mar 17, 2021 2:39:22 PM (4 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
143307
Message:

DevHDA: Restructured the input DMA code, getting rid of the FIFO bounce buffering and adding a silence pre-buffering period at the start of the stream (till we get a bit of data from the host device). bugref:9890

Location:
trunk/src/VBox/Devices/Audio
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Audio/DevHDA.cpp

    r88140 r88158  
    14401440                    AssertRC(rc2);
    14411441
    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                    }
    14461465                    hdaR3StreamMarkStarted(pDevIns, pThis, pStreamShared, tsNow);
    14471466                }
     
    52485267                                   "Number of internal DMA buffer overflows.",  "Stream%u/DMABufferOverflows", idxStream);
    52495268        else
     5269        {
    52505270            PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aStreams[idxStream].State.StatDmaFlowErrors, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES,
    52515271                                   "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        }
    52525275        PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aStreams[idxStream].State.offRead, STAMTYPE_U64, STAMVISIBILITY_USED, STAMUNIT_BYTES,
    52535276                               "Virtual internal buffer read position.",    "Stream%u/offRead", idxStream);
  • trunk/src/VBox/Devices/Audio/HDAStream.cpp

    r88137 r88158  
    4949
    5050static int  hdaR3StreamAsyncIODestroy(PHDASTREAMR3 pStreamR3);
    51 static int  hdaR3StreamAsyncIONotify(PHDASTREAMR3 pStreamR3);
    5251
    5352
     
    654653
    655654    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);
    656663
    657664    /*
     
    838845    pStreamShared->State.idxSchedule       = 0;
    839846    pStreamShared->State.idxScheduleLoop   = 0;
     847    pStreamShared->State.fInputPreBuffered = false;
    840848
    841849    if (pStreamR3->State.pCircBuf)
     
    10491057
    10501058/**
    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_DTRACE
    1087             VBOXDD_HDA_STREAM_AIO_IN((uint32_t)pStreamR3->u8SD, (uint32_t)cbDst, pStreamR3->State.offWrite);
    1088 #endif
    1089             pStreamR3->State.offWrite += cbDst;
    1090 
    1091             if (RT_LIKELY(!pStreamR3->Dbg.Runtime.fEnabled))
    1092             { /* likely */ }
    1093             else
    1094                 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 /**
    11141059 * Reads audio data from an HDA stream's DMA buffer and writes into a specified mixer sink.
    11151060 *
     
    12741219 * @param   pStreamShared       HDA stream to update (shared).
    12751220 * @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.
    12771233 */
    12781234static int hdaR3StreamDoDmaInput(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTATER3 pThisCC, PHDASTREAM pStreamShared,
    1279                                  PHDASTREAMR3 pStreamR3, uint32_t cbToProcessMax)
     1235                                 PHDASTREAMR3 pStreamR3, uint32_t cbToConsume, bool fWriteSilence, uint64_t tsNowNs)
    12801236{
    12811237    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 */ }
    12871248    else
    12881249    {
    1289         /** @todo account for this or something so we can try get back in sync
    1290          *        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_DTRACE
    1296         VBOXDD_HDA_STREAM_DMA_FLOWERROR(uSD, cbToProcessMax, pStreamShared->State.cbTransferSize,
    1297                                         hdaGetDirFromSD(uSD) == PDMAUDIODIR_OUT ? 1 : 0);
    1298 #endif
    1299     }
    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     {
    13101250        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
    13151257    {
    13161258        Log3Func(("[SD%RU8] BCIS bit set, skipping transfer\n", uSD));
     
    13191261        AssertMsgFailed(("BCIS bit for stream #%RU8 still set when it shouldn't\n", uSD));
    13201262#endif
    1321         fProceed = false;
    1322     }
    1323 
    1324     if (!fProceed)
    1325     {
    1326         hdaStreamUnlock(pStreamShared);
    13271263        return VINF_SUCCESS;
    13281264    }
    13291265
    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     */
    13451269    /* Register sanity checks. */
    13461270    Assert(uSD < HDA_MAX_STREAMS);
     
    13531277    Assert(ASMAtomicReadBool(&pStreamShared->State.fRunning));
    13541278
    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;
    13701344#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        }
    14011364        /*
    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.
    14041372         */
    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
    14131374        {
    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
    14221420#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);
    14241422#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));
    14331458        }
    14341459
    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);
    14431461
    14441462        /*
    1445          * Write to the guest.
     1463         * Is the buffer descriptor complete.
    14461464         */
    1447         if (RT_LIKELY(!pStreamR3->Dbg.Runtime.fEnabled))
    1448         { /* likely */ }
    1449         else
    1450             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 
    14651465        if (hdaR3StreamDmaBufIsComplete(pStreamShared))
    14661466        {
    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",
    14681468                      uSD, pStreamShared->State.idxCurBdle, pStreamShared->State.aBdl[pStreamShared->State.idxCurBdle].GCPhys,
    14691469                      pStreamShared->State.aBdl[pStreamShared->State.idxCurBdle].cb,
    1470                       pStreamShared->State.aBdl[pStreamShared->State.idxCurBdle].fFlags, cbDMAWritten));
     1470                      pStreamShared->State.aBdl[pStreamShared->State.idxCurBdle].fFlags));
    14711471
    14721472            /* Make sure to also update the wall clock when a BDLE is complete.
    14731473             * Needed for Windows 10 guests. */
     1474            /** @todo there is a rounding error here.   */
    14741475            hdaR3WalClkSet(pThis, pThisCC,
    14751476                             hdaWalClkGetCurrent(pThis)
    1476                            + hdaR3StreamPeriodFramesToWalClk(pPeriod,
     1477                           + hdaR3StreamPeriodFramesToWalClk(&pStreamShared->State.Period,
    14771478                                                               hdaR3StreamDmaBufGetSize(pStreamShared)
    14781479                                                             / pStreamR3->State.Mapping.cbGuestFrame),
     
    14811482            /*
    14821483             * Update the stream's current position.
     1484             *
    14831485             * Do this as accurate and close to the actual data transfer as possible.
    14841486             * All guetsts rely on this, depending on the mechanism they use (LPIB register or DMA counters).
     
    14921494            if (hdaR3StreamDmaBufNeedsIrq(pStreamShared))
    14931495            {
    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. */
    14971498                if (HDA_STREAM_REG(pThis, CTL, uSD) & HDA_SDCTL_IOCE)
    14981499                {
    14991500                    /* 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);
    15241509                }
    15251510            }
    15261511
     1512            /*
     1513             * Advance to the next BDLE.
     1514             */
    15271515            hdaR3StreamDmaBufAdvanceToNext(pStreamShared);
    15281516        }
    15291517        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",
    15311519                      uSD, pStreamShared->State.idxCurBdle, pStreamShared->State.aBdl[pStreamShared->State.idxCurBdle].GCPhys,
    15321520                      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     */
    15371530    HDA_STREAM_REG(pThis, STS, uSD) &= ~HDA_SDSTS_FIFORDY;
    15381531
    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));
    15831561    return VINF_SUCCESS;
    15841562}
    15851563
     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 */
     1573static 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}
    15861637
    15871638/**
     
    16081659                                  PHDASTREAMR3 pStreamR3, uint32_t cbToProduce, uint64_t tsNowNs)
    16091660{
    1610     PHDASTREAMPERIOD const  pPeriod = &pStreamShared->State.Period;
    1611     uint8_t const           uSD     = pStreamShared->u8SD;
     1661    uint8_t const uSD = pStreamShared->u8SD;
    16121662    LogFlowFunc(("ENTER - #%u cbToProduce=%#x\n", uSD, cbToProduce));
    16131663
     
    17141764                AssertRC(rc2);
    17151765
    1716 # ifdef HDA_DEBUG_SILENCE
     1766#ifdef HDA_DEBUG_SILENCE
    17171767                fix me if relevant;
    1718 # endif
     1768#endif
    17191769                if (RT_LIKELY(!pStreamR3->Dbg.Runtime.fEnabled))
    17201770                { /* likely */ }
     
    17221772                    DrvAudioHlpFileWrite(pStreamR3->Dbg.Runtime.pFileDMARaw, pvBufDst, cbBufDst, 0 /* fFlags */);
    17231773
     1774#ifdef VBOX_WITH_DTRACE
     1775                VBOXDD_HDA_STREAM_DMA_OUT((uint32_t)uSD, (uint32_t)cbBufDst, pStreamR3->State.offWrite);
     1776#endif
    17241777                pStreamR3->State.offWrite += cbBufDst;
    17251778                RTCircBufReleaseWriteBlock(pCircBuf, cbBufDst);
     
    17441797        {
    17451798            Assert(PDMAudioPropsIsSizeAligned(&pStreamShared->State.Cfg.Props, cbLeft));
    1746             uint32_t const cbLeftInput = PDMAudioPropsFramesToBytes(&pStreamR3->State.Mapping.GuestProps,
     1799            uint32_t const cbLeftGuest = PDMAudioPropsFramesToBytes(&pStreamR3->State.Mapping.GuestProps,
    17471800                                                                    PDMAudioPropsBytesToFrames(&pStreamShared->State.Cfg.Props,
    17481801                                                                                               cbLeft));
    1749             if (cbChunk <= cbLeftInput)
     1802            if (cbChunk <= cbLeftGuest)
    17501803            { /* very likely */ }
    17511804            else
    1752                 cbChunk = cbLeftInput;
     1805                cbChunk = cbLeftGuest;
    17531806
    17541807            /*
     
    18361889            hdaR3WalClkSet(pThis, pThisCC,
    18371890                             hdaWalClkGetCurrent(pThis)
    1838                            + hdaR3StreamPeriodFramesToWalClk(pPeriod,
     1891                           + hdaR3StreamPeriodFramesToWalClk(&pStreamShared->State.Period,
    18391892                                                               hdaR3StreamDmaBufGetSize(pStreamShared)
    18401893                                                             / pStreamR3->State.Mapping.cbGuestFrame),
     
    19081961                         RT_MIN(cFramesProcessed, hdaR3StreamPeriodGetRemainingFrames(&pStreamShared->State.Period)));
    19091962
    1910     uint64_t const cWallTicks = hdaR3StreamPeriodFramesToWalClk(pPeriod, cFramesProcessed);
     1963    uint64_t const cWallTicks = hdaR3StreamPeriodFramesToWalClk(&pStreamShared->State.Period, cFramesProcessed);
    19111964    uint64_t const uWallNew   = hdaWalClkGetCurrent(pThis) + cWallTicks;
    19121965    uint64_t const uWallMax   = hdaR3WalClkGetMax(pThis, pThisCC);
     
    22122265    else
    22132266    {
    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         */
    22162273# ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
    22172274        if (!fInTimer)
    22182275# 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);
    22652277# ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
    22662278        else /* fInTimer */
    22672279# endif
    22682280        {
     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));
    22692317# 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                }
    22782373            }
    2279 # endif
    2280             const uint32_t cbStreamUsed = hdaR3StreamGetUsed(pStreamR3);
     2374
     2375            /*
     2376             * Do the DMA'ing.
     2377             */
    22812378            if (cbStreamUsed)
    22822379            {
    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);
    22842382                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
    22852393            }
     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
    22862407        }
    22872408    }
     
    26712792 * @param   pStreamR3           HDA stream to notify async I/O thread for.
    26722793 */
    2673 static int hdaR3StreamAsyncIONotify(PHDASTREAMR3 pStreamR3)
     2794int hdaR3StreamAsyncIONotify(PHDASTREAMR3 pStreamR3)
    26742795{
    26752796    return RTSemEventSignal(pStreamR3->State.AIO.hEvent);
  • trunk/src/VBox/Devices/Audio/HDAStream.h

    r88137 r88158  
    125125    uint8_t                 cTransferPendingInterrupts;
    126126    /** 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;
    128134    /** Timestamp (absolute, in timer ticks) of the last DMA data transfer. */
    129135    uint64_t                tsTransferLast;
     
    156162    /** The start time for the playback (on the timer clock). */
    157163    uint64_t                tsStart;
     164
     165    uint64_t                au64Padding[3];
    158166
    159167    /** @name DMA engine
     
    307315        /** Counter for unresovled under/overflows problems. */
    308316        STAMCOUNTER             StatDmaFlowErrors;
     317        /** Number of bytes involved in unresolved flow errors. */
     318        STAMCOUNTER             StatDmaFlowErrorBytes;
    309319    } State;
    310320    /** Debug bits. */
     
    357367void                hdaR3StreamAsyncIOUnlock(PHDASTREAMR3 pStreamR3);
    358368void                hdaR3StreamAsyncIOEnable(PHDASTREAMR3 pStreamR3, bool fEnable);
     369int                 hdaR3StreamAsyncIONotify(PHDASTREAMR3 pStreamR3);
    359370# endif /* VBOX_WITH_AUDIO_HDA_ASYNC_IO */
    360371/** @} */
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette