VirtualBox

Changeset 73833 in vbox for trunk/src


Ignore:
Timestamp:
Aug 22, 2018 3:40:27 PM (6 years ago)
Author:
vboxsync
Message:

Audio: Async I/O fixes for HDA + AC'97.

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

Legend:

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

    r73565 r73833  
    13631363# ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
    13641364        hdaR3StreamAsyncIOLock(pStream);
    1365         hdaR3StreamAsyncIOEnable(pStream, false /* fEnable */);
    13661365# endif
    13671366        /* Make sure to remove the run bit before doing the actual stream reset. */
     
    13971396            if (fRun)
    13981397            {
    1399 # ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
    1400                 hdaR3StreamAsyncIOEnable(pStream, fRun /* fEnable */);
    1401 # endif
    14021398                /* (Re-)initialize the stream with current values. */
    14031399                rc2 = hdaR3StreamInit(pStream, pStream->u8SD);
  • trunk/src/VBox/Devices/Audio/DevIchAc97.cpp

    r73651 r73833  
    839839        rc = ichac97R3StreamAsyncIOCreate(pThis, pStream);
    840840    if (RT_SUCCESS(rc))
    841     {
    842841        ichac97R3StreamAsyncIOLock(pStream);
    843         ichac97R3StreamAsyncIOEnable(pStream, fEnable);
    844     }
    845842# endif
    846843
     
    12881285    {
    12891286        pAIO->fShutdown = false;
     1287        pAIO->fEnabled  = true; /* Enabled by default. */
    12901288
    12911289        rc = RTSemEventCreate(&pAIO->Event);
     
    14211419 * The host sink(s) set the overall pace.
    14221420 *
    1423  * This routine is called by both, the synchronous and the asynchronous, implementations.
     1421 * This routine is called by both, the synchronous and the asynchronous
     1422 * (VBOX_WITH_AUDIO_AC97_ASYNC_IO), implementations.
     1423 *
     1424 * When running synchronously, the device DMA transfers *and* the mixer sink
     1425 * processing is within the device timer.
     1426 *
     1427 * When running asynchronously, only the device DMA transfers are done in the
     1428 * device timer, whereas the mixer sink processing then is done in the stream's
     1429 * own async I/O thread. This thread also will call this function
     1430 * (with fInTimer set to @c false).
    14241431 *
    14251432 * @param   pThis               AC'97 state.
     
    14301437static void ichac97R3StreamUpdate(PAC97STATE pThis, PAC97STREAM pStream, bool fInTimer)
    14311438{
     1439    RT_NOREF(fInTimer);
     1440
    14321441    PAUDMIXSINK pSink = ichac97R3IndexToSink(pThis, pStream->u8SD);
    14331442    AssertPtr(pSink);
     
    14401449    if (pStream->u8SD == AC97SOUNDSOURCE_PO_INDEX) /* Output (SDO). */
    14411450    {
    1442 #ifdef LOG_ENABLED
    1443         const uint64_t deltaLastUpdateNs = RTTimeNanoTS() - pStream->State.tsLastUpdateNs;
    1444 #endif
    1445         pStream->State.tsLastUpdateNs = RTTimeNanoTS();
    1446 
    1447         PPDMAUDIOPCMPROPS pProps = &pStream->State.Cfg.Props;
    1448 
    1449         /* Make sure that we don't transfer more than we need for this slot. */
    1450         uint32_t cbToTransfer = DrvAudioHlpMilliToBytes(pStream->State.Cfg.Device.uSchedulingHintMs, pProps);
    1451 
    1452         /* Make sure that the transfer is frame-aligned.
    1453          * Add one additional frame to not transfer too little because of the alignment;
    1454          * ichac97R3StreamTransfer() will take care of clamping to the correct value then. */
    1455         cbToTransfer = DrvAudioHlpBytesAlign(cbToTransfer, pProps) + PDMAUDIOPCMPROPS_F2B(pProps, 1 /* Frame */);
    1456 
    1457         Log3Func(("[SD%RU8] cbToTransfer=%RU32, deltaLastUpdateNs=%RU64\n", pStream->u8SD, cbToTransfer, deltaLastUpdateNs / RT_NS_1MS));
    1458 
    1459         if (   fInTimer
    1460             && cbToTransfer)
    1461         {
    1462             /* Do the DMA transfer. */
    1463             rc2 = ichac97R3StreamTransfer(pThis, pStream, cbToTransfer);
     1451        /* How much (guest output) data is available at the moment for the AC'97 stream? */
     1452        /* Only read from the AC'97 stream at the given scheduling rate. */
     1453        bool fDoRead = false; /* Whether to read from the AC'97 stream or not. */
     1454
     1455# ifdef VBOX_WITH_AUDIO_AC97_ASYNC_IO
     1456        if (fInTimer)
     1457# endif
     1458        {
     1459            const uint32_t cbStreamFree = ichac97R3StreamGetFree(pStream);
     1460            if (cbStreamFree)
     1461            {
     1462                /* Do the DMA transfer. */
     1463                rc2 = ichac97R3StreamTransfer(pThis, pStream, cbStreamFree);
     1464                AssertRC(rc2);
     1465            }
     1466
     1467            /* Only read from the AC'97 stream at the given scheduling rate. */
     1468            const uint64_t tsNowNs = RTTimeNanoTS();
     1469            if (tsNowNs - pStream->State.tsLastUpdateNs >= pStream->State.Cfg.Device.uSchedulingHintMs * RT_NS_1MS)
     1470            {
     1471                fDoRead = true;
     1472                pStream->State.tsLastUpdateNs = tsNowNs;
     1473            }
     1474        }
     1475
     1476        Log3Func(("[SD%RU8] fInTimer=%RTbool, fDoRead=%RTbool\n", pStream->u8SD, fInTimer, fDoRead));
     1477
     1478# ifdef VBOX_WITH_AUDIO_AC97_ASYNC_IO
     1479        if (fDoRead)
     1480        {
     1481            rc2 = ichac97R3StreamAsyncIONotify(pStream);
    14641482            AssertRC(rc2);
    14651483        }
    1466 
    1467         /* Make sure that we don't write more than we need for this slot. */
    1468         uint32_t cbToWrite = RT_MIN(cbToTransfer, ichac97R3StreamGetUsed(pStream));
    1469 
    1470         /* Make sure that the write is byte-aligned. */
    1471         cbToWrite = DrvAudioHlpBytesAlign(cbToWrite, pProps);
    1472 
    1473         Log3Func(("[SD%RU8] cbToWrite=%RU32, deltaLastUpdateNs=%RU64\n", pStream->u8SD, cbToWrite, deltaLastUpdateNs / RT_NS_1MS));
     1484# endif
    14741485
    14751486# ifdef VBOX_WITH_AUDIO_AC97_ASYNC_IO
    1476         if (   fInTimer
    1477             && cbToWrite)
    1478         {
    1479             rc2 = ichac97R3StreamAsyncIONotify(pThis, pStream);
    1480             AssertRC(rc2);
    1481         }
    1482         else
     1487        if (!fInTimer) /* In async I/O thread */
     1488        {
     1489# else
     1490        if (fDoRead)
     1491        {
    14831492# endif
    1484         {
    1485             if (cbToWrite)
     1493            const uint32_t cbSinkWritable     = AudioMixerSinkGetWritable(pSink);
     1494            const uint32_t cbStreamReadable   = ichac97R3StreamGetUsed(pStream);
     1495            const uint32_t cbToReadFromStream = RT_MIN(cbStreamReadable, cbSinkWritable);
     1496
     1497            Log3Func(("[SD%RU8] cbSinkWritable=%RU32, cbStreamReadable=%RU32\n", pStream->u8SD, cbSinkWritable, cbStreamReadable));
     1498
     1499            if (cbToReadFromStream)
    14861500            {
    14871501                /* Read (guest output) data and write it to the stream's sink. */
    1488                 uint32_t cbRead;
    1489                 rc2 = ichac97R3StreamRead(pThis, pStream, pSink, cbToWrite, &cbRead);
     1502                rc2 = ichac97R3StreamRead(pThis, pStream, pSink, cbToReadFromStream, NULL);
    14901503                AssertRC(rc2);
    14911504            }
    1492 
    1493             /* When running synchronously, update the associated sink here.
    1494              * Otherwise this will be done in the device timer. */
    1495             rc2 = AudioMixerSinkUpdate(pSink);
    1496             AssertRC(rc2);
    1497 
    1498         }
     1505        }
     1506
     1507        /* When running synchronously, update the associated sink here.
     1508         * Otherwise this will be done in the async I/O thread. */
     1509        rc2 = AudioMixerSinkUpdate(pSink);
     1510        AssertRC(rc2);
    14991511    }
    15001512    else /* Input (SDI). */
  • trunk/src/VBox/Devices/Audio/HDAStream.cpp

    r73529 r73833  
    6767    rc = hdaR3StreamPeriodCreate(&pStream->State.Period);
    6868    AssertRCReturn(rc, rc);
     69
     70    pStream->State.tsLastUpdateNs = 0;
    6971
    7072#ifdef DEBUG
     
    378380        pStream->State.cTransferPendingInterrupts = 0;
    379381        pStream->State.cbDMALeft                  = 0;
     382        pStream->State.tsLastUpdateNs             = 0;
    380383
    381384        const uint64_t cTicksPerHz = TMTimerGetFreq(pStream->pTimer) / pThis->u16TimerHz;
     
    785788
    786789            Assert(cbSrc >= cbWritten);
    787             Log2Func(("[SD%RU8]: %zu/%zu bytes read\n", pStream->u8SD, cbWritten, cbSrc));
     790            Log2Func(("[SD%RU8]: %RU32/%zu bytes read\n", pStream->u8SD, cbWritten, cbSrc));
    788791        }
    789792
     
    891894    if (cbToProcess > cbToProcessMax)
    892895    {
    893         if (pStream->State.Cfg.enmDir == PDMAUDIODIR_IN)
    894             LogRelMax2(64, ("HDA: Warning: DMA buffer underflow for stream #%RU8 (still %RU32 bytes needed)\n",
    895                             pStream->u8SD, cbToProcess - cbToProcessMax));
    896         else
    897             LogRelMax2(64, ("HDA: Warning: DMA buffer overflow for stream #%RU8 (%RU32 bytes outstanding)\n",
    898                             pStream->u8SD, cbToProcess - cbToProcessMax));
    899 
    900         LogFunc(("[SD%RU8] Warning: Limiting transfer (cbToProcess=%RU32, cbToProcessMax=%RU32)\n",
     896        LogFunc(("[SD%RU8] Limiting transfer (cbToProcess=%RU32, cbToProcessMax=%RU32)\n",
    901897                 pStream->u8SD, cbToProcess, cbToProcessMax));
    902898
     
    982978            {
    983979                const uint32_t cbDMAFree = (uint32_t)RTCircBufFree(pCircBuf);
    984 
    985                 if (cbDMAFree < cbDMA)
    986                     LogRelMax2(64, ("HDA: Warning: DMA buffer overflow of stream #%RU8 (discarding %RU32 bytes)\n",
    987                                pStream->u8SD, cbDMA - cbDMAFree));
     980                Assert(cbDMAFree >= cbDMA); /* This must always hold. */
    988981
    989982#ifndef VBOX_WITH_HDA_AUDIO_INTERLEAVING_STREAMS_SUPPORT
     
    12751268 * This routine is called by both, the synchronous and the asynchronous, implementations.
    12761269 *
     1270 * This routine is called by both, the synchronous and the asynchronous
     1271 * (VBOX_WITH_AUDIO_HDA_ASYNC_IO), implementations.
     1272 *
     1273 * When running synchronously, the device DMA transfers *and* the mixer sink
     1274 * processing is within the device timer.
     1275 *
     1276 * When running asynchronously, only the device DMA transfers are done in the
     1277 * device timer, whereas the mixer sink processing then is done in the stream's
     1278 * own async I/O thread. This thread also will call this function
     1279 * (with fInTimer set to @c false).
     1280 *
    12771281 * @param   pStream             HDA stream to update.
    12781282 * @param   fInTimer            Whether to this function was called from the timer
     
    12981302    if (hdaGetDirFromSD(pStream->u8SD) == PDMAUDIODIR_OUT) /* Output (SDO). */
    12991303    {
    1300         /* Is the HDA stream ready to be written (guest output data) to? If so, by how much? */
    1301         const uint32_t cbFree = hdaR3StreamGetFree(pStream);
    1302 
    1303         if (   fInTimer
    1304             && cbFree)
    1305         {
    1306             Log3Func(("[SD%RU8] cbFree=%RU32\n", pStream->u8SD, cbFree));
    1307 
    1308             /* Do the DMA transfer. */
    1309             rc2 = hdaR3StreamTransfer(pStream, cbFree);
    1310             AssertRC(rc2);
    1311         }
    1312 
    1313         /* How much (guest output) data is available at the moment for the HDA stream? */
    1314         uint32_t cbUsed = hdaR3StreamGetUsed(pStream);
    1315 
    1316 #ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
    1317         if (   fInTimer
    1318             && cbUsed)
     1304        bool fDoRead = false; /* Whether to read from the HDA stream or not. */
     1305
     1306# ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
     1307        if (fInTimer)
     1308# endif
     1309        {
     1310            const uint32_t cbStreamFree = hdaR3StreamGetFree(pStream);
     1311            if (cbStreamFree)
     1312            {
     1313                /* Do the DMA transfer. */
     1314                rc2 = hdaR3StreamTransfer(pStream, cbStreamFree);
     1315                AssertRC(rc2);
     1316            }
     1317
     1318            /* Only read from the HDA stream at the given scheduling rate. */
     1319            const uint64_t tsNowNs = RTTimeNanoTS();
     1320            if (tsNowNs - pStream->State.tsLastUpdateNs >= pStream->State.Cfg.Device.uSchedulingHintMs * RT_NS_1MS)
     1321            {
     1322                fDoRead = true;
     1323                pStream->State.tsLastUpdateNs = tsNowNs;
     1324            }
     1325        }
     1326
     1327        Log3Func(("[SD%RU8] fInTimer=%RTbool, fDoRead=%RTbool\n", pStream->u8SD, fInTimer, fDoRead));
     1328
     1329# ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
     1330        if (fDoRead)
    13191331        {
    13201332            rc2 = hdaR3StreamAsyncIONotify(pStream);
    13211333            AssertRC(rc2);
    13221334        }
    1323         else
    1324         {
    1325 #endif
    1326             const uint32_t cbSinkWritable = AudioMixerSinkGetWritable(pSink);
    1327 
    1328             Log3Func(("[SD%RU8] cbWritable=%RU32, cbUsed=%RU32\n", pStream->u8SD, cbSinkWritable, cbUsed));
    1329 
    1330             /* Do not write more than the sink can hold at the moment.
    1331              * The host sets the overall pace. */
    1332             if (cbUsed > cbSinkWritable)
    1333                 cbUsed = cbSinkWritable;
    1334 
    1335             if (cbUsed)
     1335# endif
     1336
     1337# ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
     1338        if (!fInTimer) /* In async I/O thread */
     1339        {
     1340# else
     1341        if (fDoRead)
     1342        {
     1343# endif
     1344            const uint32_t cbSinkWritable     = AudioMixerSinkGetWritable(pSink);
     1345            const uint32_t cbStreamReadable   = hdaR3StreamGetUsed(pStream);
     1346            const uint32_t cbToReadFromStream = RT_MIN(cbStreamReadable, cbSinkWritable);
     1347
     1348            Log3Func(("[SD%RU8] cbSinkWritable=%RU32, cbStreamReadable=%RU32\n", pStream->u8SD, cbSinkWritable, cbStreamReadable));
     1349
     1350            if (cbToReadFromStream)
    13361351            {
    13371352                /* Read (guest output) data and write it to the stream's sink. */
    1338                 rc2 = hdaR3StreamRead(pStream, cbUsed, NULL /* pcbRead */);
     1353                rc2 = hdaR3StreamRead(pStream, cbToReadFromStream, NULL);
    13391354                AssertRC(rc2);
    13401355            }
    13411356
    13421357            /* When running synchronously, update the associated sink here.
    1343              * Otherwise this will be done in the stream's dedicated async I/O thread. */
     1358             * Otherwise this will be done in the async I/O thread. */
    13441359            rc2 = AudioMixerSinkUpdate(pSink);
    13451360            AssertRC(rc2);
    1346 
    1347 #ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
    1348         }
    1349 #endif
     1361        }
    13501362    }
    13511363    else /* Input (SDI). */
    13521364    {
    1353 #ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
     1365# ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
    13541366        if (!fInTimer)
    13551367        {
    1356 #endif
     1368# endif
    13571369            rc2 = AudioMixerSinkUpdate(pSink);
    13581370            AssertRC(rc2);
    13591371
    13601372            /* Is the sink ready to be read (host input data) from? If so, by how much? */
    1361             uint32_t cbReadable = AudioMixerSinkGetReadable(pSink);
     1373            uint32_t cbSinkReadable = AudioMixerSinkGetReadable(pSink);
    13621374
    13631375            /* How much (guest input) data is available for writing at the moment for the HDA stream? */
    1364             const uint32_t cbFree = hdaR3StreamGetFree(pStream);
    1365 
    1366             Log3Func(("[SD%RU8] cbReadable=%RU32, cbFree=%RU32\n", pStream->u8SD, cbReadable, cbFree));
    1367 
    1368             /* Do not write more than the sink can hold at the moment.
     1376            const uint32_t cbStreamFree = hdaR3StreamGetFree(pStream);
     1377
     1378            Log3Func(("[SD%RU8] cbSinkReadable=%RU32, cbStreamFree=%RU32\n", pStream->u8SD, cbSinkReadable, cbStreamFree));
     1379
     1380            /* Do not read more than the HDA stream can hold at the moment.
    13691381             * The host sets the overall pace. */
    1370             if (cbReadable > cbFree)
    1371                 cbReadable = cbFree;
    1372 
    1373             if (cbReadable)
     1382            if (cbSinkReadable > cbStreamFree)
     1383                cbSinkReadable = cbStreamFree;
     1384
     1385            if (cbSinkReadable)
    13741386            {
    13751387                uint8_t abFIFO[HDA_FIFO_MAX + 1];
    1376                 while (cbReadable)
     1388                while (cbSinkReadable)
    13771389                {
    13781390                    uint32_t cbRead;
    13791391                    rc2 = AudioMixerSinkRead(pSink, AUDMIXOP_COPY,
    1380                                              abFIFO, RT_MIN(cbReadable, (uint32_t)sizeof(abFIFO)), &cbRead);
     1392                                             abFIFO, RT_MIN(cbSinkReadable, (uint32_t)sizeof(abFIFO)), &cbRead);
    13811393                    AssertRCBreak(rc2);
    13821394
    13831395                    if (!cbRead)
    13841396                    {
    1385                         AssertMsgFailed(("Nothing read from sink, even if %RU32 bytes were (still) announced\n", cbReadable));
     1397                        AssertMsgFailed(("Nothing read from sink, even if %RU32 bytes were (still) announced\n", cbSinkReadable));
    13861398                        break;
    13871399                    }
     
    13981410                    }
    13991411
    1400                     Assert(cbReadable >= cbRead);
    1401                     cbReadable -= cbRead;
     1412                    Assert(cbSinkReadable >= cbRead);
     1413                    cbSinkReadable -= cbRead;
    14021414                }
    14031415            }
    1404         #if 0
    1405             else /* Send silence as input. */
    1406             {
    1407                 cbReadable = pStream->State.cbTransferSize - pStream->State.cbTransferProcessed;
    1408 
    1409                 Log3Func(("[SD%RU8] Sending silence (%RU32 bytes)\n", pStream->u8SD, cbReadable));
    1410 
    1411                 if (cbReadable)
    1412                 {
    1413                     rc2 = hdaR3StreamWrite(pStream, NULL /* Silence */, cbReadable, NULL /* pcbWritten */);
    1414                     AssertRC(rc2);
    1415                 }
    1416             }
    1417         #endif
    1418 #ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
     1416# ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
    14191417        }
    14201418        else /* fInTimer */
    14211419        {
    1422 #endif
    1423             const uint64_t tsNow = RTTimeMilliTS();
    1424             static uint64_t s_lasti = 0;
    1425             if (s_lasti == 0)
    1426                 s_lasti = tsNow;
    1427 
    1428             if (tsNow - s_lasti >= 10) /** @todo Fix this properly. */
     1420# endif
     1421
     1422# ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
     1423            const uint64_t tsNowNs = RTTimeNanoTS();
     1424            if (tsNowNs - pStream->State.tsLastUpdateNs >= pStream->State.Cfg.Device.uSchedulingHintMs * RT_NS_1MS)
    14291425            {
    14301426                rc2 = hdaR3StreamAsyncIONotify(pStream);
    14311427                AssertRC(rc2);
    14321428
    1433                 s_lasti = tsNow;
    1434             }
    1435 
    1436             const uint32_t cbToTransfer = hdaR3StreamGetUsed(pStream);
    1437             if (cbToTransfer)
    1438             {
    1439                 rc2 = hdaR3StreamTransfer(pStream, cbToTransfer);
     1429                pStream->State.tsLastUpdateNs = tsNowNs;
     1430            }
     1431# endif
     1432            const uint32_t cbStreamFree = hdaR3StreamGetUsed(pStream);
     1433            if (cbStreamFree)
     1434            {
     1435                rc2 = hdaR3StreamTransfer(pStream, cbStreamFree);
    14401436                AssertRC(rc2);
    14411437            }
    1442 #ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
    1443         }
    1444 #endif
     1438# ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
     1439        }
     1440# endif
    14451441    }
    14461442}
     
    17541750    {
    17551751        pAIO->fShutdown = false;
     1752        pAIO->fEnabled  = true; /* Enabled by default. */
    17561753
    17571754        rc = RTSemEventCreate(&pAIO->Event);
  • trunk/src/VBox/Devices/Audio/HDAStream.h

    r73370 r73833  
    177177    /** Unused, padding. */
    178178    uint8_t                 abPadding4[2+4];
     179   /** Timestamp (in ns) of last stream update. */
     180    uint64_t                tsLastUpdateNs;
    179181} HDASTREAMSTATE;
    180182AssertCompileSizeAlignment(HDASTREAMSTATE, 8);
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