VirtualBox

Changeset 73525 in vbox for trunk/src/VBox


Ignore:
Timestamp:
Aug 6, 2018 12:33:08 PM (7 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
124152
Message:

Audio/Mixer: Use a mixer sink's mixing buffer for multiplexing.

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

Legend:

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

    r73465 r73525  
    480480    LogFlowFuncEnter();
    481481
    482 #ifdef VBOX_AUDIO_MIXER_WITH_MIXBUF
    483     /* Make sure only compatible streams are added. */
    484     if (pStream->enmDir == PDMAUDIODIR_IN)
    485     {
    486         if (DrvAudioHlpPCMPropsAreEqual(&pSink->PCMProps, &pStream->InOut.pIn->Props))
    487         {
    488 #ifdef VBOX_AUDIO_MIXER_WITH_MIXBUF
    489             /* Chain: Stream (Child) -> Sink (Child) -> Guest (Parent). */
    490             PPDMAUDIOMIXBUF pHstIn = &pStream->InOut.pIn->pHstStrmIn->MixBuf;
    491             PPDMAUDIOMIXBUF pGstIn = &pStream->InOut.pIn->MixBuf;
    492 
    493             /* Unlink any former parent from host input. */
    494             AudioMixBufUnlink(pHstIn);
    495 
    496             /* Link host input to this sink as a parent. */
    497             rc = AudioMixBufLinkTo(pHstIn, &pSink->MixBuf);
    498             AssertRC(rc);
    499 
    500             /* Unlink any former parent from this sink. */
    501             AudioMixBufUnlink(&pSink->MixBuf);
    502 
    503             /* Link guest input to this sink as a parent. */
    504             rc = AudioMixBufLinkTo(&pSink->MixBuf, pGstIn);
    505             AssertRC(rc);
    506 # ifdef DEBUG
    507             AudioMixBufDbgPrintChain(&pStream->InOut.pIn->MixBuf);
    508 # endif
    509 #endif /* VBOX_AUDIO_MIXER_WITH_MIXBUF */
    510         }
    511         else
    512             AssertFailedStmt(rc = VERR_WRONG_TYPE);
    513     }
    514     else if (pStream->enmDir == PDMAUDIODIR_OUT)
    515     {
    516         if (DrvAudioHlpPCMPropsAreEqual(&pSink->PCMProps, &pStream->InOut.pOut->Props))
    517         {
    518 #ifdef VBOX_AUDIO_MIXER_WITH_MIXBUF
    519             /* Chain: Guest (Child) -> Sink (Child) -> Stream (Parent). */
    520             rc = AudioMixBufLinkTo(&pStream->InOut.pOut->pHstStrmOut->MixBuf, &pSink->MixBuf);
    521 # ifdef DEBUG
    522             AudioMixBufDbgPrintChain(&pSink->MixBuf);
    523 # endif
    524 #endif /* VBOX_AUDIO_MIXER_WITH_MIXBUF */
    525         }
    526         else
    527             AssertFailedStmt(rc = VERR_WRONG_TYPE);
    528     }
    529     else
    530         AssertFailedStmt(rc = VERR_NOT_IMPLEMENTED);
    531 #else
    532     rc = VINF_SUCCESS;
    533 #endif
     482    /** @todo Check if stream already is assigned to (another) sink. */
     483
     484    /* If the sink is running and not in pending disable mode,
     485     * make sure that the added stream also is enabled. */
     486    if (    (pSink->fStatus & AUDMIXSINK_STS_RUNNING)
     487        && !(pSink->fStatus & AUDMIXSINK_STS_PENDING_DISABLE))
     488    {
     489        rc = audioMixerStreamCtlInternal(pStream, PDMAUDIOSTREAMCMD_ENABLE, AUDMIXSTRMCTL_FLAG_NONE);
     490    }
    534491
    535492    if (RT_SUCCESS(rc))
    536493    {
    537         /** @todo Check if stream already is assigned to (another) sink. */
    538 
    539         /* If the sink is running and not in pending disable mode,
    540          * make sure that the added stream also is enabled. */
    541         if (    (pSink->fStatus & AUDMIXSINK_STS_RUNNING)
    542             && !(pSink->fStatus & AUDMIXSINK_STS_PENDING_DISABLE))
    543         {
    544             rc = audioMixerStreamCtlInternal(pStream, PDMAUDIOSTREAMCMD_ENABLE, AUDMIXSTRMCTL_FLAG_NONE);
    545         }
    546 
    547         if (RT_SUCCESS(rc))
    548         {
    549             /* Apply the sink's combined volume to the stream. */
    550             rc = pStream->pConn->pfnStreamSetVolume(pStream->pConn, pStream->pStream, &pSink->VolumeCombined);
    551             AssertRC(rc);
    552         }
    553 
    554         if (RT_SUCCESS(rc))
    555         {
    556             /* Save pointer to sink the stream is attached to. */
    557             pStream->pSink = pSink;
    558 
    559             /* Append stream to sink's list. */
    560             RTListAppend(&pSink->lstStreams, &pStream->Node);
    561             pSink->cStreams++;
    562         }
     494        /* Apply the sink's combined volume to the stream. */
     495        rc = pStream->pConn->pfnStreamSetVolume(pStream->pConn, pStream->pStream, &pSink->VolumeCombined);
     496        AssertRC(rc);
     497    }
     498
     499    if (RT_SUCCESS(rc))
     500    {
     501        /* Save pointer to sink the stream is attached to. */
     502        pStream->pSink = pSink;
     503
     504        /* Append stream to sink's list. */
     505        RTListAppend(&pSink->lstStreams, &pStream->Node);
     506        pSink->cStreams++;
    563507    }
    564508
     
    859803    if (pSink->fStatus & AUDMIXSINK_STS_RUNNING)
    860804    {
    861 #ifdef VBOX_AUDIO_MIXER_WITH_MIXBUF
     805#ifdef VBOX_AUDIO_MIXER_WITH_MIXBUF_IN
    862806# error "Implement me!"
    863807#else
     
    922866        return 0;
    923867
    924     const uint64_t deltaLastReadWriteNs = RTTimeNanoTS() - pSink->tsLastReadWrittenNs;
    925 
    926868    uint32_t cbWritable = 0;
    927869
     
    930872    {
    931873#ifdef VBOX_AUDIO_MIXER_WITH_MIXBUF
    932 # error "Implement me!"
     874        cbWritable = AudioMixBufFreeBytes(&pSink->MixBuf);
    933875#else
    934876        /* Return how much data we expect since the last write. */
    935         cbWritable = DrvAudioHlpNanoToBytes(deltaLastReadWriteNs, &pSink->PCMProps);
    936 
     877        cbWritable = DrvAudioHlpMilliToBytes(10 /* ms */, &pSink->PCMProps); /** @todo Make this configurable! */
     878#endif
    937879        /* Make sure to align the writable size to the stream's frame size. */
    938880        cbWritable = DrvAudioHlpBytesAlign(cbWritable, &pSink->PCMProps);
    939 #endif
    940     }
    941 
    942     Log3Func(("Mixer: [%s] cbWritable=%RU32 (%RU64ms)\n", pSink->pszName, cbWritable, deltaLastReadWriteNs / RT_NS_1MS_64));
     881    }
     882
     883    Log3Func(("Mixer: [%s] cbWritable=%RU32 (%RU64ms)\n",
     884              pSink->pszName, cbWritable, DrvAudioHlpBytesToMilli(cbWritable, &pSink->PCMProps)));
    943885
    944886    int rc2 = RTCritSectLeave(&pSink->CritSect);
     
    11311073            uint32_t cbReadStrm;
    11321074            AssertPtr(pStreamRecSource->pConn);
    1133 #ifdef VBOX_AUDIO_MIXER_WITH_MIXBUF
     1075#ifdef VBOX_AUDIO_MIXER_WITH_MIXBUF_IN
    11341076# error "Implement me!"
    11351077#else
     
    12091151                 pSink->pszName, pStream->pStream->szName, pSink->cStreams));
    12101152
    1211 #ifdef VBOX_AUDIO_MIXER_WITH_MIXBUF
    1212     /* Unlink mixing buffer. */
    1213     AudioMixBufUnlink(&pStream->pStream->MixBuf);
    1214 #endif
    1215 
    12161153    /* Remove stream from sink. */
    12171154    RTListNodeRemove(&pStream->Node);
     
    12841221    LogFunc(("[%s]\n", pSink->pszName));
    12851222
    1286     if (pSink->enmDir == AUDMIXSINKDIR_INPUT)
    1287     {
    12881223#ifdef VBOX_AUDIO_MIXER_WITH_MIXBUF
    1289         AudioMixBufReset(&pSink->MixBuf);
    1290 #else
    1291         pSink->In.cbReadable = 0;
     1224    AudioMixBufReset(&pSink->MixBuf);
    12921225#endif
    1293     }
    1294     else if (pSink->enmDir == AUDMIXSINKDIR_OUTPUT)
    1295     {
    1296 #ifdef VBOX_AUDIO_MIXER_WITH_MIXBUF
    1297         AudioMixBufReset(&pSink->MixBuf);
    1298 #else
    1299         pSink->Out.cbWritable = 0;
    1300 #endif
    1301     }
    13021226
    13031227    /* Update last updated timestamp. */
    1304     pSink->tsLastUpdatedMs = RTTimeMilliTS();
     1228    pSink->tsLastUpdatedMs = 0;
    13051229
    13061230    /* Reset status. */
     
    14081332    /* Also update the sink's mixing buffer format. */
    14091333    AudioMixBufDestroy(&pSink->MixBuf);
    1410     rc = AudioMixBufInit(&pSink->MixBuf, pSink->pszName, pPCMProps, _4K /** @todo Make configurable? */);
     1334    rc = AudioMixBufInit(&pSink->MixBuf, pSink->pszName, &pSink->PCMProps,
     1335                         DrvAudioHlpMilliToFrames(100 /* ms */, &pSink->PCMProps)); /** @todo Make this configurable? */
    14111336    if (RT_SUCCESS(rc))
    14121337    {
     
    16321557    }
    16331558
    1634     Log3Func(("[%s] cbReadable=%RU32, cbWritable=%RU32, rc=%Rrc\n",
    1635               pSink->pszName, pSink->In.cbReadable, pSink->Out.cbWritable, rc));
    1636 
    16371559    return rc;
    16381560}
     
    17021624
    17031625/**
    1704  * Writes data to a mixer sink.
     1626 * Writes audio output data to all connected mixer streams (multiplex).
    17051627 *
    17061628 * @returns IPRT status code.
    1707  * @param   pSink               Sink to write data to.
    1708  * @param   enmOp               Mixer operation to use when writing data to the sink.
    1709  * @param   pvBuf               Buffer containing the audio data to write.
    1710  * @param   cbBuf               Size (in bytes) of the buffer containing the audio data.
    1711  * @param   pcbWritten          Number of bytes written. Optional.
    1712  */
    1713 int AudioMixerSinkWrite(PAUDMIXSINK pSink, AUDMIXOP enmOp, const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten)
    1714 {
    1715     AssertPtrReturn(pSink, VERR_INVALID_POINTER);
     1629 * @param   pSink               Sink to write audio output to.
     1630 * @param   enmOp               What mixing operation to use. Currently not implemented.
     1631 * @param   pvBuf               Pointer to audio data to write.
     1632 * @param   cbBuf               Size (in bytes) of audio data to write.
     1633 * @param   pcbWrittenMin       Returns minimum size (in bytes) successfully written by all mixer streams. Optional.
     1634 */
     1635int audioMixerSinkWriteToStreams(PAUDMIXSINK pSink, AUDMIXOP enmOp, const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWrittenMin)
     1636{
    17161637    RT_NOREF(enmOp);
    1717     AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
    1718     AssertReturn   (cbBuf, VERR_INVALID_PARAMETER);
    1719     /* pcbWritten is optional. */
    1720 
    1721     int rc = RTCritSectEnter(&pSink->CritSect);
    1722     if (RT_FAILURE(rc))
    1723         return rc;
    1724 
    1725     AssertMsg(pSink->fStatus & AUDMIXSINK_STS_RUNNING,
    1726               ("%s: Can't write to a sink which is not running (anymore) (status 0x%x)\n", pSink->pszName, pSink->fStatus));
    1727     AssertMsg(pSink->enmDir == AUDMIXSINKDIR_OUTPUT,
    1728               ("%s: Can't write to a sink which is not an output sink\n", pSink->pszName));
     1638
     1639    int rc = VINF_SUCCESS;
     1640
     1641    uint32_t cbWrittenMin = UINT32_MAX;
    17291642
    17301643    PAUDMIXSTREAM pMixStream;
     
    17601673            LogFunc(("[%s] Warning: Only written %RU32/%RU32 bytes for stream '%s'\n",
    17611674                     pSink->pszName, cbWritten, cbBuf, pMixStream->pszName));
    1762             LogRel2(("Audio: Buffer overrun for mixer sink '%s', stream '%s'\n", pSink->pszName, pMixStream->pszName));
     1675            LogRel2(("Audio: Buffer overrun for mixer stream '%s' (sink '%s')\n", pMixStream->pszName, pSink->pszName));
    17631676#ifdef DEBUG_andy
    17641677            AssertFailed();
    17651678#endif
    17661679        }
     1680
     1681        cbWrittenMin = RT_MIN(cbWrittenMin, cbWritten);
    17671682
    17681683        if (cbWritten) /* Update the mixer stream's last written time stamp. */
     
    18041719            cbToWrite -= (uint32_t)cbChunk;
    18051720        }
    1806 
    1807         if (RTCircBufUsed(pCircBuf))
    1808         {
    1809             /* Set dirty bit. */
    1810             pSink->fStatus |= AUDMIXSINK_STS_DIRTY;
    1811         }
    1812     }
     1721    }
     1722
     1723    if (cbWrittenMin == UINT32_MAX) /* Nothing written? */
     1724        cbWrittenMin = 0;
     1725
     1726    if (pcbWrittenMin)
     1727        *pcbWrittenMin = cbWrittenMin;
     1728
     1729    return rc;
     1730}
     1731
     1732/**
     1733 * Writes data to a mixer sink.
     1734 *
     1735 * @returns IPRT status code.
     1736 * @param   pSink               Sink to write data to.
     1737 * @param   enmOp               Mixer operation to use when writing data to the sink.
     1738 * @param   pvBuf               Buffer containing the audio data to write.
     1739 * @param   cbBuf               Size (in bytes) of the buffer containing the audio data.
     1740 * @param   pcbWritten          Number of bytes written. Optional.
     1741 */
     1742int AudioMixerSinkWrite(PAUDMIXSINK pSink, AUDMIXOP enmOp, const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten)
     1743{
     1744    AssertPtrReturn(pSink, VERR_INVALID_POINTER);
     1745    RT_NOREF(enmOp);
     1746    AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
     1747    AssertReturn   (cbBuf, VERR_INVALID_PARAMETER);
     1748    /* pcbWritten is optional. */
     1749
     1750    int rc = RTCritSectEnter(&pSink->CritSect);
     1751    if (RT_FAILURE(rc))
     1752        return rc;
     1753
     1754    AssertMsg(pSink->fStatus & AUDMIXSINK_STS_RUNNING,
     1755              ("%s: Can't write to a sink which is not running (anymore) (status 0x%x)\n", pSink->pszName, pSink->fStatus));
     1756    AssertMsg(pSink->enmDir == AUDMIXSINKDIR_OUTPUT,
     1757              ("%s: Can't write to a sink which is not an output sink\n", pSink->pszName));
     1758
     1759#ifdef VBOX_AUDIO_MIXER_WITH_MIXBUF
     1760    uint32_t cbWritten = 0;
     1761    uint32_t cbToWrite = cbBuf;
     1762    while (cbToWrite)
     1763    {
     1764        /* First, write the data to the mixer sink's own mixing buffer.
     1765         * Here the audio data can be transformed into the mixer sink's format. */
     1766        uint32_t cfWritten = 0;
     1767        rc = AudioMixBufWriteCirc(&pSink->MixBuf, (uint8_t *)pvBuf + cbWritten, cbToWrite, &cfWritten);
     1768        if (RT_FAILURE(rc))
     1769            break;
     1770
     1771        const uint32_t cbWrittenChunk = DrvAudioHlpFramesToBytes(cfWritten, &pSink->PCMProps);
     1772
     1773        Assert(cbToWrite >= cbWrittenChunk);
     1774        cbToWrite -= cbWrittenChunk;
     1775        cbWritten += cbWrittenChunk;
     1776    }
     1777
     1778    Assert(cbWritten <= cbBuf);
     1779
     1780    if (   RT_FAILURE(rc)
     1781        || cbWritten < cbBuf)
     1782    {
     1783        LogRel2(("Audio: Buffer overrun for mixer sink '%s' (only %RU32/%RU32 bytes written)\n",
     1784                 pSink->pszName, cbWritten, cbBuf));
     1785# ifdef DEBUG_andy
     1786        AssertFailed();
     1787# endif
     1788    }
     1789
     1790    /* Next, try to write (multiplex) as much audio data as possible to all connected mixer streams. */
     1791    uint8_t arrChunkBuf[_1K]; /** @todo Hm ... some zero copy / shared buffers would be nice! */
     1792    while (cbWritten)
     1793    {
     1794        uint32_t cfChunk;
     1795        rc  = AudioMixBufAcquireReadBlock(&pSink->MixBuf, arrChunkBuf, sizeof(arrChunkBuf), &cfChunk);
     1796        if (RT_FAILURE(rc))
     1797            break;
     1798
     1799        const uint32_t cbChunk = DrvAudioHlpFramesToBytes(cfChunk, &pSink->PCMProps);
     1800        Assert(cbChunk <= sizeof(arrChunkBuf));
     1801        rc = audioMixerSinkWriteToStreams(pSink, enmOp, arrChunkBuf, cbChunk, NULL /* pcbWrittenMin */);
     1802        AudioMixBufReleaseReadBlock(&pSink->MixBuf, cfChunk);
     1803
     1804        Assert(cbWritten >= cbChunk);
     1805        cbWritten -= cbChunk;
     1806    }
     1807
     1808    if (   !(pSink->fStatus & AUDMIXSINK_STS_DIRTY)
     1809        && AudioMixBufUsed(&pSink->MixBuf)) /* Still audio output data left? Consider the sink as being "dirty" then. */
     1810    {
     1811        /* Set dirty bit. */
     1812        pSink->fStatus |= AUDMIXSINK_STS_DIRTY;
     1813    }
     1814#else
     1815    rc = audioMixerSinkWriteToStreams(pSink, enmOp, pvBuf, cbBuf, NULL /* pcbWrittenMin */);
     1816#endif /* VBOX_AUDIO_MIXER_WITH_MIXBUF */
    18131817
    18141818    /* Update the sink's last written time stamp. */
  • trunk/src/VBox/Devices/Audio/AudioMixer.h

    r73421 r73525  
    2626
    2727#include <VBox/vmm/pdmaudioifs.h>
     28
     29/* Use a mixer sink's mixing buffer for multiplexing. */
     30#define VBOX_AUDIO_MIXER_WITH_MIXBUF
    2831
    2932/**
     
    136139typedef struct AUDMIXSINKIN
    137140{
    138 #ifdef VBOX_AUDIO_MIXER_WITH_MIXBUF
    139     /** This sink's mixing buffer, acting as
    140      * a parent buffer for all streams this sink owns. */
    141     PDMAUDIOMIXBUF MixBuf;
    142 #else
    143     /** Number of bytes available to read from the sink. */
    144     uint32_t       cbReadable;
    145 #endif
    146141    /** The current recording source. Can be NULL if not set. */
    147142    PAUDMIXSTREAM  pStreamRecSource;
     
    154149typedef struct AUDMIXSINKOUT
    155150{
    156 #ifdef VBOX_AUDIO_MIXER_WITH_MIXBUF
    157     /** This sink's mixing buffer, acting as
    158      * a parent buffer for all streams this sink owns. */
    159     PDMAUDIOMIXBUF MixBuf;
    160 #else
    161     /** Number of bytes available to write to the sink. */
    162     uint32_t       cbWritable;
    163 #endif
    164151} AUDMIXSINKOUT;
    165152
     
    179166    /** The sink's critical section. */
    180167    RTCRITSECT              CritSect;
     168#ifdef VBOX_AUDIO_MIXER_WITH_MIXBUF
     169    /** This sink's mixing buffer, acting as
     170     * a parent buffer for all streams this sink owns. */
     171    PDMAUDIOMIXBUF          MixBuf;
     172#endif
    181173    /** Union for input/output specifics. */
    182174    union
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