VirtualBox

Changeset 57571 in vbox


Ignore:
Timestamp:
Aug 27, 2015 3:37:33 PM (9 years ago)
Author:
vboxsync
Message:

Audio/CoreAudio: Fix cracks and lost samples when the sample rates between guest and the output device don't match. Samples at the end of pvPCMBuf could be lost in case the circular buffer has not enough room at the end. Eliminate the temporary PCM buffer

File:
1 edited

Legend:

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

    r57451 r57571  
    277277    /* A ring buffer for transferring data to the playback thread. */
    278278    PRTCIRCBUF                  pBuf;
    279     /* Temporary buffer for copying over audio data into Core Audio. */
    280     void                       *pvPCMBuf;
    281     /** Size of the temporary buffer. */
    282     size_t                      cbPCMBuf;
    283279    /* Initialization status tracker. Used when some of the device parameters
    284280     * or the device itself is changed during the runtime. */
     
    12611257    if (RT_SUCCESS(rc))
    12621258    {
    1263         /* Allocate temporary buffer. */
    1264         pStreamOut->cbPCMBuf = _4K; /** @todo Make this configurable. */
    1265         pStreamOut->pvPCMBuf = RTMemAlloc(pStreamOut->cbPCMBuf);
    1266         if (!pStreamOut->pvPCMBuf)
    1267             rc = VERR_NO_MEMORY;
    1268     }
    1269 
    1270     if (RT_SUCCESS(rc))
    1271     {
    12721259        /*
    12731260         * Register callbacks.
     
    15041491    int rc = VINF_SUCCESS;
    15051492    uint32_t cbReadTotal = 0;
    1506 
    1507     do
    1508     {
    1509         size_t cbMixBuf = AudioMixBufSizeBytes(&pHstStrmOut->MixBuf);
    1510         size_t cbBuf    = RT_MIN(cbMixBuf, pStreamOut->cbPCMBuf);
    1511         size_t cbToRead = RT_MIN(cbBuf, RTCircBufFree(pStreamOut->pBuf));
    1512         LogFlowFunc(("cbToRead=%zu\n", cbToRead));
    1513 
     1493    uint32_t cAvail = AudioMixBufAvail(&pHstStrmOut->MixBuf);
     1494    size_t cbAvail  = AUDIOMIXBUF_S2B(&pHstStrmOut->MixBuf, cAvail);
     1495    size_t cbToRead = RT_MIN(cbAvail, RTCircBufFree(pStreamOut->pBuf));
     1496    LogFlowFunc(("cbToRead=%zu\n", cbToRead));
     1497
     1498    while (cbToRead)
     1499    {
    15141500        uint32_t cRead, cbRead;
    15151501        uint8_t *puBuf;
    1516         size_t   cbToWrite;
    1517 
    1518         while (cbToRead)
    1519         {
    1520             rc = AudioMixBufReadCirc(&pHstStrmOut->MixBuf,
    1521                                      pStreamOut->pvPCMBuf, cbToRead, &cRead);
    1522             if (   RT_FAILURE(rc)
    1523                 || !cRead)
    1524                 break;
    1525 
    1526             cbRead = AUDIOMIXBUF_S2B(&pHstStrmOut->MixBuf, cRead);
    1527 
    1528             /* Try to acquire the necessary space from the ring buffer. */
    1529             RTCircBufAcquireWriteBlock(pStreamOut->pBuf, cbRead, (void **)&puBuf, &cbToWrite);
    1530             if (!cbToWrite)
    1531             {
    1532                 RTCircBufReleaseWriteBlock(pStreamOut->pBuf, cbToWrite);
    1533                 break;
    1534             }
    1535 
    1536             /* Transfer data into stream's own ring buffer. The playback will operate on this
    1537              * own ring buffer separately. */
    1538             Assert(cbToWrite <= cbRead);
    1539             memcpy(puBuf, pStreamOut->pvPCMBuf, cbToWrite);
    1540 
    1541             /* Release the ring buffer, so the read thread could start reading this data. */
    1542             RTCircBufReleaseWriteBlock(pStreamOut->pBuf, cbToWrite);
    1543 
    1544             Assert(cbToRead >= cbRead);
    1545             cbToRead -= cbRead;
    1546             cbReadTotal += cbRead;
    1547         }
    1548     }
    1549     while (0);
     1502        size_t   cbCopy;
     1503
     1504        /* Try to acquire the necessary space from the ring buffer. */
     1505        RTCircBufAcquireWriteBlock(pStreamOut->pBuf, cbToRead, (void **)&puBuf, &cbCopy);
     1506        if (!cbCopy)
     1507        {
     1508            RTCircBufReleaseWriteBlock(pStreamOut->pBuf, cbCopy);
     1509            break;
     1510        }       
     1511
     1512        Assert(cbCopy <= cbToRead);
     1513
     1514        rc = AudioMixBufReadCirc(&pHstStrmOut->MixBuf,
     1515                                 puBuf, cbCopy, &cRead);
     1516
     1517        if (   RT_FAILURE(rc)
     1518            || !cRead)
     1519        {
     1520            RTCircBufReleaseWriteBlock(pStreamOut->pBuf, 0);
     1521            break;
     1522        }
     1523
     1524        cbRead = AUDIOMIXBUF_S2B(&pHstStrmOut->MixBuf, cRead);
     1525
     1526        /* Release the ring buffer, so the read thread could start reading this data. */
     1527        RTCircBufReleaseWriteBlock(pStreamOut->pBuf, cbRead);
     1528
     1529        Assert(cbToRead >= cbRead);
     1530        cbToRead -= cbRead;
     1531        cbReadTotal += cbRead;
     1532    }
    15501533
    15511534    if (RT_SUCCESS(rc))
     
    18601843                pStreamOut->audioUnit = NULL;
    18611844                pStreamOut->deviceID  = kAudioDeviceUnknown;
    1862 
    1863                 if (pStreamOut->pvPCMBuf)
    1864                 {
    1865                     RTMemFree(pStreamOut->pvPCMBuf);
    1866                     pStreamOut->pvPCMBuf = NULL;
    1867                     pStreamOut->cbPCMBuf = 0;
    1868                 }
    18691845
    18701846                ASMAtomicXchgU32(&pStreamOut->status, CA_STATUS_UNINIT);
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