VirtualBox

Changeset 88950 in vbox for trunk/src/VBox/Devices/Audio


Ignore:
Timestamp:
May 8, 2021 11:38:30 PM (4 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
144285
Message:

DevIchAc97: Used the asynchronous I/O facility of the mixer sink. bugref:9890

File:
1 edited

Legend:

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

    r88940 r88950  
    357357    /** Circular buffer (FIFO) for holding DMA'ed data. */
    358358    R3PTRTYPE(PRTCIRCBUF)   pCircBuf;
     359    /** Current circular buffer read offset (for tracing & logging). */
     360    uint64_t                offRead;
     361    /** Current circular buffer write offset (for tracing & logging). */
     362    uint64_t                offWrite;
    359363#if HC_ARCH_BITS == 32
    360364    uint32_t                Padding;
     
    362366    /** The stream's current configuration. */
    363367    PDMAUDIOSTREAMCFG       Cfg; //+108
    364     /** Asynchronous I/O state members. */
    365     AC97STREAMSTATEAIO      AIO;
    366368    /** Timestamp of the last DMA data transfer. */
    367369    uint64_t                tsTransferLast;
     
    377379     *  Set in R3StreamInit(). */
    378380    uint16_t                uTimerHz;
    379     uint8_t                 Padding3[2];
     381    /** Set if we've registered the asynchronous update job. */
     382    bool                    fRegisteredAsyncUpdateJob;
     383    uint8_t                 Padding3;
    380384    /** (Virtual) clock ticks per transfer. */
    381385    uint64_t                cTransferTicks;
    382    /** Timestamp (in ns) of last stream update. */
     386    /** Timestamp (in ns) of last stream update. */
    383387    uint64_t                tsLastUpdateNs;
     388
     389    /** Size of the DMA buffer (pCircBuf) in bytes. */
     390    uint32_t                StatDmaBufSize;
     391    /** Number of used bytes in the DMA buffer (pCircBuf). */
     392    uint32_t                StatDmaBufUsed;
    384393} AC97STREAMSTATE;
    385394AssertCompileSizeAlignment(AC97STREAMSTATE, 8);
     
    685694static int                ichac97R3StreamTransfer(PPDMDEVINS pDevIns, PAC97STATE pThis, PAC97STREAM pStream,
    686695                                                  PAC97STREAMR3 pStreamCC, uint32_t cbToProcessMax);
    687 static void               ichac97R3StreamUpdate(PPDMDEVINS pDevIns, PAC97STATE pThis, PAC97STATER3 pThisCC, PAC97STREAM pStream,
    688                                                 PAC97STREAMR3 pStreamCC, bool fInTimer);
     696static DECLCALLBACK(void) ichac97R3StreamUpdateAsyncIoJob(PPDMDEVINS pDevIns, PAUDMIXSINK pSink, void *pvUser);
    689697
    690698static DECLCALLBACK(void) ichac97R3Reset(PPDMDEVINS pDevIns);
     
    692700static void               ichac97R3MixerRemoveDrvStreams(PPDMDEVINS pDevIns, PAC97STATER3 pThisCC, PAUDMIXSINK pMixSink,
    693701                                                         PDMAUDIODIR enmDir, PDMAUDIODSTSRCUNION dstSrc);
    694 
    695 static int                ichac97R3StreamAsyncIOCreate(PAC97STATE pThis, PAC97STATER3 pThisCC, PAC97STREAM pStream, PAC97STREAMR3 pStreamCC);
    696 static int                ichac97R3StreamAsyncIODestroy(PAC97STATE pThis, PAC97STREAMR3 pStreamCC);
    697 static void               ichac97R3StreamAsyncIOLock(PAC97STREAMR3 pStreamCC);
    698 static void               ichac97R3StreamAsyncIOUnlock(PAC97STREAMR3 pStreamCC);
    699 /*static void               ichac97R3StreamAsyncIOEnable(PAC97STREAM pStream, bool fEnable); Unused */
    700702
    701703DECLINLINE(PDMAUDIODIR)   ichac97GetDirFromSD(uint8_t uSD);
     
    973975{
    974976    ichac97R3StreamLock(pStreamCC);
     977    PAUDMIXSINK const pSink = ichac97R3IndexToSink(pThisCC, pStream->u8SD);
     978    AudioMixerSinkLock(pSink);
    975979
    976980    int rc = VINF_SUCCESS;
    977981    if (fEnable)
    978         rc = ichac97R3StreamAsyncIOCreate(pThis, pThisCC, pStream, pStreamCC);
    979     if (RT_SUCCESS(rc))
    980     {
    981         ichac97R3StreamAsyncIOLock(pStreamCC);
    982         if (fEnable)
     982    {
     983        if (pStreamCC->State.pCircBuf)
     984            RTCircBufReset(pStreamCC->State.pCircBuf);
     985
     986        rc = ichac97R3StreamOpen(pDevIns, pThis, pThisCC, pStream, pStreamCC, false /* fForce */);
     987
     988        /* Re-register the update job with the AIO thread with correct sched hint.
     989           Note! We do not unregister it on disable because of draining. */
     990        if (pStreamCC->State.fRegisteredAsyncUpdateJob)
     991            AudioMixerSinkRemoveUpdateJob(pSink, ichac97R3StreamUpdateAsyncIoJob, pStreamCC);
     992        int rc2 = AudioMixerSinkAddUpdateJob(pSink, ichac97R3StreamUpdateAsyncIoJob, pStreamCC,
     993                                             pStreamCC->State.Cfg.Device.cMsSchedulingHint);
     994        AssertRC(rc2);
     995        pStreamCC->State.fRegisteredAsyncUpdateJob = RT_SUCCESS(rc2) || rc2 == VERR_ALREADY_EXISTS;
     996
     997        /* Open debug files: */
     998        if (RT_LIKELY(!pStreamCC->Dbg.Runtime.fEnabled))
     999        { /* likely */ }
     1000        else
    9831001        {
    984             if (pStreamCC->State.pCircBuf)
    985                 RTCircBufReset(pStreamCC->State.pCircBuf);
    986 
    987             rc = ichac97R3StreamOpen(pDevIns, pThis, pThisCC, pStream, pStreamCC, false /* fForce */);
    988 
    989             if (RT_LIKELY(!pStreamCC->Dbg.Runtime.fEnabled))
    990             { /* likely */ }
    991             else
     1002            if (!AudioHlpFileIsOpen(pStreamCC->Dbg.Runtime.pFileStream))
    9921003            {
    993                 if (!AudioHlpFileIsOpen(pStreamCC->Dbg.Runtime.pFileStream))
    994                 {
    995                     int rc2 = AudioHlpFileOpen(pStreamCC->Dbg.Runtime.pFileStream, AUDIOHLPFILE_DEFAULT_OPEN_FLAGS,
    996                                                &pStreamCC->State.Cfg.Props);
    997                     AssertRC(rc2);
    998                 }
    999 
    1000                 if (!AudioHlpFileIsOpen(pStreamCC->Dbg.Runtime.pFileDMA))
    1001                 {
    1002                     int rc2 = AudioHlpFileOpen(pStreamCC->Dbg.Runtime.pFileDMA, AUDIOHLPFILE_DEFAULT_OPEN_FLAGS,
    1003                                                &pStreamCC->State.Cfg.Props);
    1004                     AssertRC(rc2);
    1005                 }
     1004                rc2 = AudioHlpFileOpen(pStreamCC->Dbg.Runtime.pFileStream, AUDIOHLPFILE_DEFAULT_OPEN_FLAGS,
     1005                                       &pStreamCC->State.Cfg.Props);
     1006                AssertRC(rc2);
     1007            }
     1008
     1009            if (!AudioHlpFileIsOpen(pStreamCC->Dbg.Runtime.pFileDMA))
     1010            {
     1011                rc2 = AudioHlpFileOpen(pStreamCC->Dbg.Runtime.pFileDMA, AUDIOHLPFILE_DEFAULT_OPEN_FLAGS,
     1012                                       &pStreamCC->State.Cfg.Props);
     1013                AssertRC(rc2);
    10061014            }
    10071015        }
    1008         else
    1009             rc = ichac97R3StreamClose(pStream);
    1010 
    1011         if (RT_SUCCESS(rc))
    1012         {
    1013             /* First, enable or disable the stream and the stream's sink, if any. */
    1014             rc = AudioMixerSinkEnable(ichac97R3IndexToSink(pThisCC, pStream->u8SD), fEnable);
    1015         }
    1016 
    1017         ichac97R3StreamAsyncIOUnlock(pStreamCC);
     1016    }
     1017    else
     1018        rc = ichac97R3StreamClose(pStream);
     1019
     1020    if (RT_SUCCESS(rc))
     1021    {
     1022        /* First, enable or disable the stream and the stream's sink, if any. */
     1023        rc = AudioMixerSinkEnable(pSink, fEnable);
    10181024    }
    10191025
    10201026    /* Make sure to leave the lock before (eventually) starting the timer. */
     1027    AudioMixerSinkUnlock(pSink);
    10211028    ichac97R3StreamUnlock(pStreamCC);
    10221029    LogFunc(("[SD%RU8] fEnable=%RTbool, rc=%Rrc\n", pStream->u8SD, fEnable, rc));
     
    11201127 *
    11211128 * @returns VBox status code.
    1122  * @param   pThis               The shared AC'97 state.
     1129 * @param   pThisCC             The ring-3 AC'97 state.
    11231130 * @param   pStream             The AC'97 stream to destroy (shared).
    11241131 * @param   pStreamCC           The AC'97 stream to destroy (ring-3).
    11251132 */
    1126 static void ichac97R3StreamDestroy(PAC97STATE pThis, PAC97STREAM pStream, PAC97STREAMR3 pStreamCC)
     1133static void ichac97R3StreamDestroy(PAC97STATER3 pThisCC, PAC97STREAM pStream, PAC97STREAMR3 pStreamCC)
    11271134{
    11281135    LogFlowFunc(("[SD%RU8]\n", pStream->u8SD));
     
    11331140    AssertRC(rc2);
    11341141
    1135     rc2 = ichac97R3StreamAsyncIODestroy(pThis, pStreamCC);
    1136     AssertRC(rc2);
     1142    if (pStreamCC->State.fRegisteredAsyncUpdateJob)
     1143    {
     1144        PAUDMIXSINK pSink = ichac97R3IndexToSink(pThisCC, pStream->u8SD);
     1145        if (pSink)
     1146            AudioMixerSinkRemoveUpdateJob(pSink, ichac97R3StreamUpdateAsyncIoJob, pStreamCC);
     1147        pStreamCC->State.fRegisteredAsyncUpdateJob = false;
     1148    }
    11371149
    11381150    if (RT_LIKELY(!pStreamCC->Dbg.Runtime.fEnabled))
     
    11711183     */
    11721184    for (unsigned i = 0; i < AC97_MAX_STREAMS; i++)
    1173         ichac97R3StreamDestroy(pThis, &pThis->aStreams[i], &pThisCC->aStreams[i]);
     1185        ichac97R3StreamDestroy(pThisCC, &pThis->aStreams[i], &pThisCC->aStreams[i]);
    11741186
    11751187    /*
    11761188     * Destroy all sinks.
    11771189     */
    1178 
    1179     PDMAUDIODSTSRCUNION dstSrc;
     1190    PDMAUDIODSTSRCUNION dstSrc; /** @todo r=bird: this is just impractical. combine the two enums into one, they already have no overlapping values. */
    11801191    if (pThisCC->pSinkLineIn)
    11811192    {
     
    12061217}
    12071218
    1208 /**
    1209  * Writes audio data from a mixer sink into an AC'97 stream's DMA buffer.
    1210  *
    1211  * @returns VBox status code.
    1212  * @param   pDstStreamCC        The AC'97 stream to write to (ring-3).
    1213  * @param   pSrcMixSink         Mixer sink to get audio data to write from.
    1214  * @param   cbToWrite           Number of bytes to write.
    1215  * @param   pcbWritten          Number of bytes written. Optional.
    1216  */
    1217 static int ichac97R3StreamWrite(PAC97STREAMR3 pDstStreamCC, PAUDMIXSINK pSrcMixSink, uint32_t cbToWrite, uint32_t *pcbWritten)
    1218 {
    1219     AssertPtrReturn(pSrcMixSink, VERR_INVALID_POINTER);
    1220     AssertReturn(cbToWrite > 0,  VERR_INVALID_PARAMETER);
    1221     /* pcbWritten is optional. */
    1222 
    1223     PRTCIRCBUF pCircBuf = pDstStreamCC->State.pCircBuf;
    1224     AssertPtr(pCircBuf);
    1225 
    1226     uint32_t cbRead = 0;
    1227 
    1228     void    *pvDst;
    1229     size_t   cbDst;
    1230     RTCircBufAcquireWriteBlock(pCircBuf, cbToWrite, &pvDst, &cbDst);
    1231 
    1232     if (cbDst)
    1233     {
    1234         int rc2 = AudioMixerSinkRead(pSrcMixSink, AUDMIXOP_COPY, pvDst, (uint32_t)cbDst, &cbRead);
    1235         AssertRC(rc2);
    1236 
    1237         if (RT_LIKELY(!pDstStreamCC->Dbg.Runtime.fEnabled))
    1238         { /* likely */ }
    1239         else
    1240             AudioHlpFileWrite(pDstStreamCC->Dbg.Runtime.pFileStream, pvDst, cbRead, 0 /* fFlags */);
    1241     }
    1242 
    1243     RTCircBufReleaseWriteBlock(pCircBuf, cbRead);
    1244 
    1245     if (pcbWritten)
    1246         *pcbWritten = cbRead;
    1247 
    1248     return VINF_SUCCESS;
    1249 }
    1250 
    1251 /**
    1252  * Reads audio data from an AC'97 stream's DMA buffer and writes into a specified mixer sink.
    1253  *
    1254  * @returns VBox status code.
    1255  * @param   pSrcStreamCC        AC'97 stream to read audio data from (ring-3).
    1256  * @param   pDstMixSink         Mixer sink to write audio data to.
    1257  * @param   cbToRead            Number of bytes to read.
    1258  * @param   pcbRead             Number of bytes read. Optional.
    1259  */
    1260 static int ichac97R3StreamRead(PAC97STREAMR3 pSrcStreamCC, PAUDMIXSINK pDstMixSink, uint32_t cbToRead, uint32_t *pcbRead)
    1261 {
    1262     AssertPtrReturn(pDstMixSink, VERR_INVALID_POINTER);
    1263     AssertReturn(cbToRead > 0, VERR_INVALID_PARAMETER);
    1264     /* pcbRead is optional. */
    1265 
    1266     PRTCIRCBUF pCircBuf = pSrcStreamCC->State.pCircBuf;
    1267     AssertPtr(pCircBuf);
    1268 
    1269     void *pvSrc;
    1270     size_t cbSrc;
    1271 
    1272     int rc = VINF_SUCCESS;
    1273 
    1274     uint32_t cbReadTotal = 0;
    1275     uint32_t cbLeft      = RT_MIN(cbToRead, (uint32_t)RTCircBufUsed(pCircBuf));
    1276 
    1277     while (cbLeft)
    1278     {
    1279         uint32_t cbWritten = 0;
    1280 
    1281         RTCircBufAcquireReadBlock(pCircBuf, cbLeft, &pvSrc, &cbSrc);
    1282 
    1283         if (cbSrc)
    1284         {
    1285             if (RT_LIKELY(!pSrcStreamCC->Dbg.Runtime.fEnabled))
    1286             { /* likely */ }
    1287             else
    1288                 AudioHlpFileWrite(pSrcStreamCC->Dbg.Runtime.pFileStream, pvSrc, cbSrc, 0 /* fFlags */);
    1289 
    1290             rc = AudioMixerSinkWrite(pDstMixSink, AUDMIXOP_COPY, pvSrc, (uint32_t)cbSrc, &cbWritten);
    1291             AssertRC(rc);
    1292 
    1293             Assert(cbSrc >= cbWritten);
    1294             Log3Func(("[SD%RU8] %RU32/%zu bytes read\n", pSrcStreamCC->u8SD, cbWritten, cbSrc));
    1295         }
    1296 
    1297         RTCircBufReleaseReadBlock(pCircBuf, cbWritten);
    1298 
    1299         if (   !cbWritten /* Nothing written? */
    1300             || RT_FAILURE(rc))
    1301             break;
    1302 
    1303         Assert(cbLeft  >= cbWritten);
    1304         cbLeft         -= cbWritten;
    1305 
    1306         cbReadTotal    += cbWritten;
    1307     }
    1308 
    1309     if (pcbRead)
    1310         *pcbRead = cbReadTotal;
    1311 
    1312     return rc;
    1313 }
    1314 
    1315 
    1316 /**
    1317  * Asynchronous I/O thread for an AC'97 stream.
    1318  * This will do the heavy lifting work for us as soon as it's getting notified by another thread.
    1319  *
    1320  * @returns VBox status code.
    1321  * @param   hThreadSelf         Thread handle.
    1322  * @param   pvUser              User argument. Must be of type PAC97STREAMTHREADCTX.
    1323  */
    1324 static DECLCALLBACK(int) ichac97R3StreamAsyncIOThread(RTTHREAD hThreadSelf, void *pvUser)
    1325 {
    1326     PAC97STREAMTHREADCTX    pCtx = (PAC97STREAMTHREADCTX)pvUser;
    1327     PAC97STATE              pThis     = pCtx->pThis;
    1328     PAC97STATER3            pThisCC   = pCtx->pThisCC;
    1329     PAC97STREAM             pStream   = pCtx->pStream;
    1330     PAC97STREAMR3           pStreamCC = pCtx->pStreamCC;
    1331     PAC97STREAMSTATEAIO     pAIO      = &pStreamCC->State.AIO;
    1332 
    1333     ASMAtomicXchgBool(&pAIO->fStarted, true);
    1334 
    1335     RTThreadUserSignal(hThreadSelf);
    1336 
    1337     LogFunc(("[SD%RU8] Started\n", pStream->u8SD));
    1338 
    1339     for (;;)
    1340     {
    1341         Log2Func(("[SD%RU8] Waiting ...\n", pStream->u8SD));
    1342 
    1343         int rc2 = RTSemEventWait(pAIO->Event, RT_INDEFINITE_WAIT);
    1344         if (RT_FAILURE(rc2))
    1345             break;
    1346 
    1347         if (ASMAtomicReadBool(&pAIO->fShutdown))
    1348             break;
    1349 
    1350         rc2 = RTCritSectEnter(&pAIO->CritSect);
    1351         if (RT_SUCCESS(rc2))
    1352         {
    1353             if (!pAIO->fEnabled)
    1354             {
    1355                 RTCritSectLeave(&pAIO->CritSect);
    1356                 continue;
    1357             }
    1358 
    1359             ichac97R3StreamUpdate(pThisCC->pDevIns, pThis, pThisCC, pStream, pStreamCC, false /* fInTimer */);
    1360 
    1361             int rc3 = RTCritSectLeave(&pAIO->CritSect);
    1362             AssertRC(rc3);
    1363         }
    1364 
    1365         AssertRC(rc2);
    1366     }
    1367 
    1368     LogFunc(("[SD%RU8] Ended\n", pStream->u8SD));
    1369 
    1370     ASMAtomicXchgBool(&pAIO->fStarted, false);
    1371 
    1372     RTMemFree(pCtx);
    1373     pCtx = NULL;
    1374 
    1375     return VINF_SUCCESS;
    1376 }
    1377 
    1378 /**
    1379  * Creates the async I/O thread for a specific AC'97 audio stream.
    1380  *
    1381  * @returns VBox status code.
    1382  * @param   pThis               The shared AC'97 state (shared).
    1383  * @param   pThisCC             The shared AC'97 state (ring-3).
    1384  * @param   pStream             AC'97 audio stream to create the async I/O thread for (shared).
    1385  * @param   pStreamCC           AC'97 audio stream to create the async I/O thread for (ring-3).
    1386  */
    1387 static int ichac97R3StreamAsyncIOCreate(PAC97STATE pThis, PAC97STATER3 pThisCC, PAC97STREAM pStream, PAC97STREAMR3 pStreamCC)
    1388 {
    1389     PAC97STREAMSTATEAIO pAIO = &pStreamCC->State.AIO;
    1390 
    1391     int rc;
    1392 
    1393     if (!ASMAtomicReadBool(&pAIO->fStarted))
    1394     {
    1395         pAIO->fShutdown = false;
    1396         pAIO->fEnabled  = true; /* Enabled by default. */
    1397 
    1398         rc = RTSemEventCreate(&pAIO->Event);
    1399         if (RT_SUCCESS(rc))
    1400         {
    1401             rc = RTCritSectInit(&pAIO->CritSect);
    1402             if (RT_SUCCESS(rc))
    1403             {
    1404 /** @todo r=bird:
    1405  *        Why aren't this code using the PDM threads (PDMDevHlpThreadCreate)?
    1406  *        They would help you with managing stuff like VM suspending, resuming
    1407  *        and powering off.
    1408  *
    1409  *        Finally, just create the threads at construction time. */
    1410                 PAC97STREAMTHREADCTX pCtx = (PAC97STREAMTHREADCTX)RTMemAllocZ(sizeof(AC97STREAMTHREADCTX));
    1411                 if (pCtx)
    1412                 {
    1413                     pCtx->pStream   = pStream;
    1414                     pCtx->pStreamCC = pStreamCC;
    1415                     pCtx->pThis     = pThis;
    1416                     pCtx->pThisCC   = pThisCC;
    1417 
    1418                     rc = RTThreadCreateF(&pAIO->Thread, ichac97R3StreamAsyncIOThread, pCtx, 0 /*cbStack*/, RTTHREADTYPE_IO,
    1419                                          RTTHREADFLAGS_WAITABLE | RTTHREADFLAGS_COM_MTA, "ac97AIO%RU8", pStreamCC->u8SD);
    1420                     if (RT_SUCCESS(rc))
    1421                         rc = RTThreadUserWait(pAIO->Thread, 30 * 1000 /* 30s timeout */);
    1422                 }
    1423                 else
    1424                     rc = VERR_NO_MEMORY;
    1425             }
    1426         }
    1427     }
    1428     else
    1429         rc = VINF_SUCCESS;
    1430 
    1431     LogFunc(("[SD%RU8] Returning %Rrc\n", pStreamCC->u8SD, rc));
    1432     return rc;
    1433 }
    1434 
    1435 /**
    1436  * Lets the stream's async I/O thread know that there is some data to process.
    1437  *
    1438  * @returns VBox status code.
    1439  * @param   pStreamCC             The AC'97 stream to notify async I/O thread
    1440  *                                for (ring-3).
    1441  */
    1442 static int ichac97R3StreamAsyncIONotify(PAC97STREAMR3 pStreamCC)
    1443 {
    1444     LogFunc(("[SD%RU8]\n", pStreamCC->u8SD));
    1445     return RTSemEventSignal(pStreamCC->State.AIO.Event);
    1446 }
    1447 
    1448 /**
    1449  * Destroys the async I/O thread of a specific AC'97 audio stream.
    1450  *
    1451  * @returns VBox status code.
    1452  * @param   pThis       The shared AC'97 state.
    1453  * @param   pStreamR3   AC'97 audio stream to destroy the async I/O thread for.
    1454  */
    1455 static int ichac97R3StreamAsyncIODestroy(PAC97STATE pThis, PAC97STREAMR3 pStreamR3)
    1456 {
    1457     RT_NOREF(pThis);
    1458 
    1459     PAC97STREAMSTATEAIO pAIO = &pStreamR3->State.AIO;
    1460 
    1461     if (!ASMAtomicReadBool(&pAIO->fStarted))
    1462         return VINF_SUCCESS;
    1463 
    1464     ASMAtomicWriteBool(&pAIO->fShutdown, true);
    1465 
    1466     int rc = ichac97R3StreamAsyncIONotify(pStreamR3);
    1467     AssertRC(rc);
    1468 
    1469     int rcThread;
    1470     rc = RTThreadWait(pAIO->Thread, 30 * 1000 /* 30s timeout */, &rcThread);
    1471     LogFunc(("Async I/O thread ended with %Rrc (%Rrc)\n", rc, rcThread));
    1472 
    1473     if (RT_SUCCESS(rc))
    1474     {
    1475         rc = RTCritSectDelete(&pAIO->CritSect);
    1476         AssertRC(rc);
    1477 
    1478         rc = RTSemEventDestroy(pAIO->Event);
    1479         AssertRC(rc);
    1480 
    1481         pAIO->fStarted  = false;
    1482         pAIO->fShutdown = false;
    1483         pAIO->fEnabled  = false;
    1484     }
    1485 
    1486     LogFunc(("[SD%RU8] Returning %Rrc\n", pStreamR3->u8SD, rc));
    1487     return rc;
    1488 }
    1489 
    1490 /**
    1491  * Locks the async I/O thread of a specific AC'97 audio stream.
    1492  *
    1493  * @param   pStreamCC           AC'97 stream to lock async I/O thread for.
    1494  */
    1495 static void ichac97R3StreamAsyncIOLock(PAC97STREAMR3 pStreamCC)
    1496 {
    1497     PAC97STREAMSTATEAIO pAIO = &pStreamCC->State.AIO;
    1498 
    1499     if (!ASMAtomicReadBool(&pAIO->fStarted))
    1500         return;
    1501 
    1502     int rc2 = RTCritSectEnter(&pAIO->CritSect);
    1503     AssertRC(rc2);
    1504 }
    1505 
    1506 /**
    1507  * Unlocks the async I/O thread of a specific AC'97 audio stream.
    1508  *
    1509  * @param   pStreamCC           AC'97 stream to unlock async I/O thread for.
    1510  */
    1511 static void ichac97R3StreamAsyncIOUnlock(PAC97STREAMR3 pStreamCC)
    1512 {
    1513     PAC97STREAMSTATEAIO pAIO = &pStreamCC->State.AIO;
    1514 
    1515     if (!ASMAtomicReadBool(&pAIO->fStarted))
    1516         return;
    1517 
    1518     int rc2 = RTCritSectLeave(&pAIO->CritSect);
    1519     AssertRC(rc2);
    1520 }
    1521 
    1522 #if 0 /* Unused */
    1523 /**
    1524  * Enables (resumes) or disables (pauses) the async I/O thread.
    1525  *
    1526  * @param   pStream             AC'97 stream to enable/disable async I/O thread for.
    1527  * @param   fEnable             Whether to enable or disable the I/O thread.
    1528  *
    1529  * @remarks Does not do locking.
    1530  */
    1531 static void ichac97R3StreamAsyncIOEnable(PAC97STREAM pStream, bool fEnable)
    1532 {
    1533     PAC97STREAMSTATEAIO pAIO = &pStreamCC->State.AIO;
    1534     ASMAtomicXchgBool(&pAIO->fEnabled, fEnable);
    1535 }
     1219
     1220/**
     1221 * Input streams: Pulls data from the mixer, putting it in the internal DMA
     1222 * buffer.
     1223 *
     1224 * @param   pStreamR3       HDA stream to update (ring-3 bits).
     1225 * @param   pSink           The mixer sink to pull from.
     1226 */
     1227static void ichac97R3StreamPullFromMixer(PAC97STREAMR3 pStreamR3, PAUDMIXSINK pSink)
     1228{
     1229#ifdef LOG_ENABLED
     1230    uint64_t const offWriteOld = pStreamR3->State.offWrite;
    15361231#endif
     1232    pStreamR3->State.offWrite = AudioMixerSinkTransferFromCircBuf(pSink,
     1233                                                                  pStreamR3->State.pCircBuf,
     1234                                                                  pStreamR3->State.offWrite,
     1235                                                                  pStreamR3->u8SD,
     1236                                                                  pStreamR3->Dbg.Runtime.fEnabled
     1237                                                                  ? pStreamR3->Dbg.Runtime.pFileStream : NULL);
     1238
     1239    Log3Func(("[SD%RU8] transferred=%#RX64 bytes -> @%#RX64\n", pStreamR3->u8SD,
     1240              pStreamR3->State.offWrite - offWriteOld, pStreamR3->State.offWrite));
     1241
     1242    /* Update buffer stats. */
     1243    pStreamR3->State.StatDmaBufUsed = (uint32_t)RTCircBufUsed(pStreamR3->State.pCircBuf);
     1244}
     1245
     1246
     1247/**
     1248 * Output streams: Pushes data to the mixer.
     1249 *
     1250 * @param   pStreamR3       HDA stream to update (ring-3 bits).
     1251 * @param   pSink           The mixer sink to push to.
     1252 */
     1253static void ichac97R3StreamPushToMixer(PAC97STREAMR3 pStreamR3, PAUDMIXSINK pSink)
     1254{
     1255#ifdef LOG_ENABLED
     1256    uint64_t const offReadOld = pStreamR3->State.offRead;
     1257#endif
     1258    pStreamR3->State.offRead = AudioMixerSinkTransferFromCircBuf(pSink,
     1259                                                                 pStreamR3->State.pCircBuf,
     1260                                                                 pStreamR3->State.offRead,
     1261                                                                 pStreamR3->u8SD,
     1262                                                                 pStreamR3->Dbg.Runtime.fEnabled
     1263                                                                 ? pStreamR3->Dbg.Runtime.pFileStream : NULL);
     1264
     1265    Log3Func(("[SD%RU8] transferred=%#RX64 bytes -> @%#RX64\n", pStreamR3->u8SD,
     1266              pStreamR3->State.offRead - offReadOld, pStreamR3->State.offRead));
     1267
     1268    /* Update buffer stats. */
     1269    pStreamR3->State.StatDmaBufUsed = (uint32_t)RTCircBufUsed(pStreamR3->State.pCircBuf);
     1270}
     1271
    15371272
    15381273# ifdef LOG_ENABLED
     
    15701305
    15711306/**
    1572  * Updates an AC'97 stream by doing its required data transfers.
    1573  * The host sink(s) set the overall pace.
    1574  *
    1575  * This routine is called by both, the synchronous and the asynchronous
    1576  * implementations.
    1577  *
    1578  * When running synchronously, the device DMA transfers *and* the mixer sink
    1579  * processing is within the device timer.
    1580  *
    1581  * When running asynchronously, only the device DMA transfers are done in the
    1582  * device timer, whereas the mixer sink processing then is done in the stream's
    1583  * own async I/O thread. This thread also will call this function
    1584  * (with fInTimer set to @c false).
     1307 * Updates an AC'97 stream by doing its DMA transfers.
     1308 *
     1309 * The host sink(s) set the overall pace (bird: no it doesn't, the DMA timer
     1310 * does - we just hope like heck it matches the speed at which the *backend*
     1311 * host audio driver processes samples).
    15851312 *
    15861313 * @param   pDevIns             The device instance.
     
    15891316 * @param   pStream             The AC'97 stream to update (shared).
    15901317 * @param   pStreamCC           The AC'97 stream to update (ring-3).
    1591  * @param   fInTimer            Whether to this function was called from the timer
    1592  *                              context or an asynchronous I/O stream thread (if supported).
    1593  */
    1594 static void ichac97R3StreamUpdate(PPDMDEVINS pDevIns, PAC97STATE pThis, PAC97STATER3 pThisCC,
    1595                                   PAC97STREAM pStream, PAC97STREAMR3 pStreamCC, bool fInTimer)
    1596 {
    1597     RT_NOREF(fInTimer);
    1598 
     1318 */
     1319static void ichac97R3StreamUpdateDma(PPDMDEVINS pDevIns, PAC97STATE pThis, PAC97STATER3 pThisCC,
     1320                                     PAC97STREAM pStream, PAC97STREAMR3 pStreamCC)
     1321{
     1322    int         rc2;
    15991323    PAUDMIXSINK pSink = ichac97R3IndexToSink(pThisCC, pStream->u8SD);
    16001324    AssertPtr(pSink);
    1601 
    1602     if (!AudioMixerSinkIsActive(pSink)) /* No sink available? Bail out. */
    1603         return;
    1604 
    1605     int rc2;
    1606 
    1607     if (pStreamCC->State.Cfg.enmDir == PDMAUDIODIR_OUT) /* Output (SDO). */
    1608     {
    1609         if (fInTimer)
     1325    if (AudioMixerSinkIsActive(pSink))
     1326    {
     1327        if (pStreamCC->State.Cfg.enmDir == PDMAUDIODIR_OUT) /* Output (SDO). */
    16101328        {
    1611             const uint32_t cbStreamFree = ichac97R3StreamGetFree(pStreamCC);
     1329            uint32_t cbStreamFree = ichac97R3StreamGetFree(pStreamCC);
     1330            if (cbStreamFree)
     1331            { /* likely */ }
     1332            else
     1333            {
     1334                /** @todo Record this as a statistic. Try make some space available.    */
     1335            }
    16121336            if (cbStreamFree)
    16131337            {
     
    16251349                pStreamCC->State.tsLastUpdateNs = RTTimeNanoTS();
    16261350            }
     1351
     1352            rc2 = AudioMixerSinkSignalUpdateJob(pSink);
     1353            AssertRC(rc2);
    16271354        }
    1628 
    1629         Log3Func(("[SD%RU8] fInTimer=%RTbool\n", pStream->u8SD, fInTimer));
    1630 
    1631         rc2 = ichac97R3StreamAsyncIONotify(pStreamCC);
    1632         AssertRC(rc2);
    1633 
    1634         if (!fInTimer) /* In async I/O thread */
     1355        else /* Input (SDI). */
    16351356        {
    1636             const uint32_t cbSinkWritable     = AudioMixerSinkGetWritable(pSink);
    1637             const uint32_t cbStreamReadable   = ichac97R3StreamGetUsed(pStreamCC);
    1638             const uint32_t cbToReadFromStream = RT_MIN(cbStreamReadable, cbSinkWritable);
    1639 
    1640             Log3Func(("[SD%RU8] cbSinkWritable=%RU32, cbStreamReadable=%RU32\n", pStream->u8SD, cbSinkWritable, cbStreamReadable));
    1641 
    1642             if (cbToReadFromStream)
    1643             {
    1644                 /* Read (guest output) data and write it to the stream's sink. */
    1645                 rc2 = ichac97R3StreamRead(pStreamCC, pSink, cbToReadFromStream, NULL /* pcbRead */);
    1646                 AssertRC(rc2);
    1647             }
    1648         }
    1649         /* When running synchronously, update the associated sink here.
    1650          * Otherwise this will be done in the async I/O thread. */
    1651         rc2 = AudioMixerSinkUpdate(pSink);
    1652         AssertRC(rc2);
    1653     }
    1654     else /* Input (SDI). */
    1655     {
    1656         if (!fInTimer)
    1657         {
    1658             rc2 = AudioMixerSinkUpdate(pSink);
    1659             AssertRC(rc2);
    1660 
    1661             /* Is the sink ready to be read (host input data) from? If so, by how much? */
    1662             uint32_t cbSinkReadable = AudioMixerSinkGetReadable(pSink);
    1663 
    1664             /* How much (guest input) data is available for writing at the moment for the AC'97 stream? */
    1665             uint32_t cbStreamFree = ichac97R3StreamGetFree(pStreamCC);
    1666 
    1667             Log3Func(("[SD%RU8] cbSinkReadable=%RU32, cbStreamFree=%RU32\n", pStream->u8SD, cbSinkReadable, cbStreamFree));
    1668 
    1669             /* Do not read more than the sink can provide at the moment.
    1670              * The host sets the overall pace. */
    1671             if (cbSinkReadable > cbStreamFree)
    1672                 cbSinkReadable = cbStreamFree;
    1673 
    1674             if (cbSinkReadable)
    1675             {
    1676                 /* Write (guest input) data to the stream which was read from stream's sink before. */
    1677                 rc2 = ichac97R3StreamWrite(pStreamCC, pSink, cbSinkReadable, NULL /* pcbWritten */);
    1678                 AssertRC(rc2);
    1679             }
    1680         }
    1681         else /* fInTimer */
    1682         {
    1683 
     1357#if 0 /* bird: I just love when crusial code like this with no explanation.  This just causing AIO
     1358       *       skipping a DMA timer cycle if the timer callback is a bit quicker than the 'hint' (see HDA/9890).   */
    16841359            const uint64_t tsNowNs = RTTimeNanoTS();
    16851360            if (tsNowNs - pStreamCC->State.tsLastUpdateNs >= pStreamCC->State.Cfg.Device.cMsSchedulingHint * RT_NS_1MS)
    16861361            {
    1687                 rc2 = ichac97R3StreamAsyncIONotify(pStreamCC);
     1362                rc2 = AudioMixerSinkSignalUpdateJob(pSink);
    16881363                AssertRC(rc2);
    16891364
    16901365                pStreamCC->State.tsLastUpdateNs = tsNowNs;
    16911366            }
    1692 
    1693             const uint32_t cbStreamUsed = ichac97R3StreamGetUsed(pStreamCC);
     1367#endif
     1368
     1369            uint32_t cbStreamUsed = ichac97R3StreamGetUsed(pStreamCC);
     1370            if (cbStreamUsed)
     1371            { /* likey */ }
     1372            else
     1373            {
     1374                /** @todo Record this as a statistic. Try pull some data into the DMA buffer.*/
     1375            }
     1376
    16941377            if (cbStreamUsed)
    16951378            {
     
    16991382                AssertRC(rc2);
    17001383            }
     1384
     1385            /*
     1386             * We should always kick the AIO thread.
     1387             */
     1388            /** @todo This isn't entirely ideal.  If we get into an underrun situation,
     1389             *        we ideally want the AIO thread to run right before the DMA timer
     1390             *        rather than right after it ran. */
     1391            Log5Func(("Notifying AIO thread\n"));
     1392            rc2 = AudioMixerSinkSignalUpdateJob(pSink);
     1393            AssertRC(rc2);
     1394            pStreamCC->State.tsLastUpdateNs = RTTimeNanoTS();
    17011395        }
    17021396    }
     1397}
     1398
     1399
     1400/**
     1401 * @callback_method_impl{FNRTTHREAD, Asynchronous I/O thread for an AC'97 stream.}
     1402 *
     1403 * For output streams this moves data from the internal DMA buffer (in which
     1404 * ichac97R3StreamUpdateDma put it), thru the mixer and to the various backend
     1405 * audio devices.
     1406 *
     1407 * For input streams this pulls data from the backend audio device(s), thru the
     1408 * mixer and puts it in the internal DMA buffer ready for
     1409 * ichac97R3StreamUpdateDma to pump into guest memory.
     1410 */
     1411static DECLCALLBACK(void) ichac97R3StreamUpdateAsyncIoJob(PPDMDEVINS pDevIns, PAUDMIXSINK pSink, void *pvUser)
     1412{
     1413    PAC97STATER3 const  pThisCC   = PDMDEVINS_2_DATA_CC(pDevIns, PAC97STATER3);
     1414    PAC97STREAMR3 const pStreamCC = (PAC97STREAMR3)pvUser;
     1415    uintptr_t const     idxStream = pStreamCC - &pThisCC->aStreams[0];
     1416    Assert(pStreamCC->u8SD == idxStream);
     1417    Assert(pSink == ichac97R3IndexToSink(pThisCC, (uint8_t)idxStream));
     1418
     1419    /*
     1420     * Output (SDO).
     1421     */
     1422    if (pStreamCC->State.Cfg.enmDir == PDMAUDIODIR_OUT)
     1423        ichac97R3StreamPushToMixer(pStreamCC, pSink);
     1424    /*
     1425     * Input (SDI).
     1426     */
     1427    else
     1428        ichac97R3StreamPullFromMixer(pStreamCC, pSink);
    17031429}
    17041430
     
    21871913                if (RT_SUCCESS(rc))
    21881914                {
     1915                    pStreamCC->State.StatDmaBufSize = (uint32_t)RTCircBufSize(pStreamCC->State.pCircBuf);
     1916
    21891917                    ichac97R3MixerRemoveDrvStreams(pDevIns, pThisCC, pMixSink, Cfg.enmDir, Cfg.u);
    2190 
    21911918                    rc = ichac97R3MixerAddDrvStreams(pDevIns, pThisCC, pMixSink, &Cfg);
    21921919                    if (RT_SUCCESS(rc))
     
    27202447    Assert(PDMDevHlpTimerIsLockOwner(pDevIns, pStream->hTimer));
    27212448
    2722     ichac97R3StreamUpdate(pDevIns, pThis, pThisCC, pStream, pStreamCC, true /* fInTimer */);
     2449    ichac97R3StreamUpdateDma(pDevIns, pThis, pThisCC, pStream, pStreamCC);
    27232450
    27242451    PAUDMIXSINK pSink = ichac97R3IndexToSink(pThisCC, pStream->u8SD);
Note: See TracChangeset for help on using the changeset viewer.

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