VirtualBox

Ignore:
Timestamp:
May 10, 2016 1:27:44 PM (9 years ago)
Author:
vboxsync
Message:

Audio: Update on infrastructure:

  • More work on HDA stream interleaving + surround support
  • The mixer can now (optionally) act as a supplemental layer between audio connector interface and device emulation (where applicable)
  • Multiple LUN streams can be bound to a certain sink, which in turn then can be treated as separate input/output channels
  • Unified more code which was duplicated between different audio device emulations
  • Tiny bit of documentation

Work in progress.

File:
1 edited

Legend:

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

    r60353 r60925  
    44 *             emulations to achieve proper multiplexing from/to attached
    55 *             devices LUNs.
     6 *
     7 * This mixer acts as a layer between the audio connector interface and
     8 * the actual device emulation, providing mechanisms for audio sources (input) and
     9 * audio sinks (output).
     10 *
     11 * As audio driver instances are handled as LUNs on the device level, this
     12 * audio mixer then can take care of e.g. mixing various inputs/outputs to/from
     13 * a specific source/sink.
     14 *
     15 * How and which audio streams are connected to sinks/sources depends on how
     16 * the audio mixer has been set up.
     17 *
     18 * A sink can connect multiple output streams together, whereas a source
     19 * does this with input streams. Each sink / source consists of one or more
     20 * so-called mixer streams, which then in turn have pointers to the actual
     21 * PDM audio input/output streams.
    622 */
    723
     
    3248#include <iprt/string.h>
    3349
    34 static int audioMixerUpdateSinkVolume(PAUDMIXSINK pSink, const PPDMAUDIOVOLUME pVolMaster);
    35 
    36 
    37 int AudioMixerAddSink(PAUDIOMIXER pMixer, const char *pszName, AUDMIXSINKDIR enmDir, PAUDMIXSINK *ppSink)
     50static void audioMixerSinkDestroyInternal(PAUDMIXSINK pSink);
     51static int audioMixerSinkUpdateVolume(PAUDMIXSINK pSink, const PPDMAUDIOVOLUME pVolMaster);
     52static void audioMixerSinkRemoveStreamInternal(PAUDMIXSINK pSink, PAUDMIXSTREAM pStream);
     53
     54static void audioMixerStreamDestroyInternal(PAUDMIXSTREAM pStream);
     55static void audioMixerStreamFree(PAUDMIXSTREAM pStream);
     56
     57int AudioMixerCreateSink(PAUDIOMIXER pMixer, const char *pszName, AUDMIXSINKDIR enmDir, PAUDMIXSINK *ppSink)
    3858{
    3959    AssertPtrReturn(pMixer, VERR_INVALID_POINTER);
    4060    AssertPtrReturn(pszName, VERR_INVALID_POINTER);
    41     /** ppSink is optional. */
     61    /* ppSink is optional. */
    4262
    4363    int rc = VINF_SUCCESS;
     
    80100}
    81101
    82 int AudioMixerAddStreamIn(PAUDMIXSINK pSink, PPDMIAUDIOCONNECTOR pConnector, PPDMAUDIOGSTSTRMIN pStream,
    83                           uint32_t uFlags, PAUDMIXSTREAM *ppStream)
    84 {
    85     AssertPtrReturn(pSink, VERR_INVALID_POINTER);
    86     AssertPtrReturn(pStream, VERR_INVALID_POINTER);
    87     /** @todo Add flag validation. */
    88     /* ppStream is optional. */
    89 
    90     int rc;
    91 
    92     if (pSink->cStreams == UINT8_MAX) /* 255 streams per sink max. */
    93         return VERR_TOO_MUCH_DATA;
    94 
    95     PAUDMIXSTREAM pMixStream
    96         = (PAUDMIXSTREAM)RTMemAllocZ(sizeof(AUDMIXSTREAM));
    97     if (pMixStream)
    98     {
    99         pMixStream->pConn = pConnector;
    100         pMixStream->pIn   = pStream;
    101         /** @todo Process flags. */
    102 
    103         RTListAppend(&pSink->lstStreams, &pMixStream->Node);
    104         pSink->cStreams++;
    105 
    106         LogFlowFunc(("%s: pStream=%p, cStreams=%RU8\n",
    107                      pSink->pszName, pMixStream, pSink->cStreams));
    108 
    109         /* Increase the stream's reference count to let others know
    110          * we're reyling on it to be around now. */
    111         pStream->State.cRefs++;
    112 
    113         if (ppStream)
    114             *ppStream = pMixStream;
    115 
    116         rc = VINF_SUCCESS;
    117     }
    118     else
    119         rc = VERR_NO_MEMORY;
    120 
    121     return rc;
    122 }
    123 
    124 int AudioMixerAddStreamOut(PAUDMIXSINK pSink, PPDMIAUDIOCONNECTOR pConnector, PPDMAUDIOGSTSTRMOUT pStream,
    125                            uint32_t uFlags, PAUDMIXSTREAM *ppStream)
    126 {
    127     AssertPtrReturn(pSink, VERR_INVALID_POINTER);
    128     AssertPtrReturn(pStream, VERR_INVALID_POINTER);
    129     /** @todo Add flag validation. */
    130     /* ppStream is optional. */
    131 
    132     int rc;
    133 
    134     if (pSink->cStreams == UINT8_MAX) /* 255 streams per sink max. */
    135         return VERR_TOO_MUCH_DATA;
    136 
    137     PAUDMIXSTREAM pMixStream
    138         = (PAUDMIXSTREAM)RTMemAllocZ(sizeof(AUDMIXSTREAM));
    139     if (pMixStream)
    140     {
    141         pMixStream->pConn = pConnector;
    142         pMixStream->pOut  = pStream;
    143         /** @todo Process flags. */
    144 
    145         RTListAppend(&pSink->lstStreams, &pMixStream->Node);
    146         pSink->cStreams++;
    147 
    148         LogFlowFunc(("%s: pStream=%p, cStreams=%RU8\n",
    149                      pSink->pszName, pMixStream, pSink->cStreams));
    150 
    151         /* Increase the stream's reference count to let others know
    152          * we're reyling on it to be around now. */
    153         pStream->State.cRefs++;
    154 
    155         if (ppStream)
    156             *ppStream = pMixStream;
    157 
    158         rc = VINF_SUCCESS;
    159     }
    160     else
    161         rc = VERR_NO_MEMORY;
    162 
    163     return rc;
    164 }
    165 
    166 int AudioMixerControlStream(PAUDIOMIXER pMixer, PAUDMIXSTREAM pHandle)
    167 {
    168     return VERR_NOT_IMPLEMENTED;
    169 }
    170 
    171102int AudioMixerCreate(const char *pszName, uint32_t uFlags, PAUDIOMIXER *ppMixer)
    172103{
     
    207138}
    208139
     140void AudioMixerDebug(PAUDIOMIXER pMixer, PCDBGFINFOHLP pHlp, const char *pszArgs)
     141{
     142    PAUDMIXSINK pSink;
     143    unsigned    iSink = 0;
     144
     145    pHlp->pfnPrintf(pHlp, "[Master] %s: lVol=%u, rVol=%u, fMuted=%RTbool\n", pMixer->pszName,
     146                    pMixer->VolMaster.uLeft, pMixer->VolMaster.uRight, pMixer->VolMaster.fMuted);
     147
     148    RTListForEach(&pMixer->lstSinks, pSink, AUDMIXSINK, Node)
     149    {
     150        pHlp->pfnPrintf(pHlp, "[Sink %u] %s: lVol=%u, rVol=%u, fMuted=%RTbool\n", iSink, pSink->pszName,
     151                        pSink->Volume.uLeft, pSink->Volume.uRight, pSink->Volume.fMuted);
     152        ++iSink;
     153    }
     154}
     155
    209156void AudioMixerDestroy(PAUDIOMIXER pMixer)
    210157{
     
    216163    PAUDMIXSINK pSink, pSinkNext;
    217164    RTListForEachSafe(&pMixer->lstSinks, pSink, pSinkNext, AUDMIXSINK, Node)
    218         AudioMixerRemoveSink(pMixer, pSink);
    219 
    220     Assert(pMixer->cSinks == 0);
     165        audioMixerSinkDestroyInternal(pSink);
    221166
    222167    if (pMixer->pszName)
     
    227172
    228173    RTMemFree(pMixer);
    229 }
    230 
    231 static void audioMixerDestroySink(PAUDMIXSINK pSink)
     174    pMixer = NULL;
     175}
     176
     177int AudioMixerGetDeviceFormat(PAUDIOMIXER pMixer, PPDMAUDIOSTREAMCFG pCfg)
     178{
     179    AssertPtrReturn(pMixer, VERR_INVALID_POINTER);
     180    AssertPtrReturn(pCfg,   VERR_INVALID_POINTER);
     181
     182    /** @todo Perform a deep copy, if needed. */
     183    *pCfg = pMixer->devFmt;
     184
     185    return VINF_SUCCESS;
     186}
     187
     188void AudioMixerInvalidate(PAUDIOMIXER pMixer)
     189{
     190    AssertPtrReturnVoid(pMixer);
     191
     192    LogFlowFunc(("%s: Invalidating ...\n", pMixer->pszName));
     193
     194    /* Propagate new master volume to all connected sinks. */
     195    PAUDMIXSINK pSink;
     196    RTListForEach(&pMixer->lstSinks, pSink, AUDMIXSINK, Node)
     197    {
     198        int rc2 = audioMixerSinkUpdateVolume(pSink, &pMixer->VolMaster);
     199        AssertRC(rc2);
     200    }
     201}
     202
     203void AudioMixerRemoveSink(PAUDIOMIXER pMixer, PAUDMIXSINK pSink)
     204{
     205    AssertPtrReturnVoid(pMixer);
     206    if (!pSink)
     207        return;
     208
     209    /** @todo Check if pSink is part of pMixer. */
     210
     211    AudioMixerSinkRemoveAllStreams(pSink);
     212
     213    Assert(pSink->cStreams == 0);
     214
     215    RTListNodeRemove(&pSink->Node);
     216
     217    Assert(pMixer->cSinks);
     218    pMixer->cSinks--;
     219
     220    LogFlowFunc(("%s: pSink=%s, cSinks=%RU8\n",
     221                 pMixer->pszName, pSink->pszName, pMixer->cSinks));
     222}
     223
     224int AudioMixerSetDeviceFormat(PAUDIOMIXER pMixer, PPDMAUDIOSTREAMCFG pCfg)
     225{
     226    AssertPtrReturn(pMixer, VERR_INVALID_POINTER);
     227    AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
     228
     229    /** @todo Perform a deep copy, if needed. */
     230    pMixer->devFmt = *pCfg;
     231
     232    return VINF_SUCCESS;
     233}
     234
     235/**
     236 * Sets the mixer's master volume.
     237 *
     238 * @returns IPRT status code.
     239 * @param   pMixer          Mixer to set master volume for.
     240 * @param   pVol            Volume to set.
     241 */
     242int AudioMixerSetMasterVolume(PAUDIOMIXER pMixer, PPDMAUDIOVOLUME pVol)
     243{
     244    AssertPtrReturn(pMixer, VERR_INVALID_POINTER);
     245    AssertPtrReturn(pVol,   VERR_INVALID_POINTER);
     246
     247    pMixer->VolMaster = *pVol;
     248
     249    LogFlowFunc(("%s: lVol=%RU32, rVol=%RU32 => fMuted=%RTbool, lVol=%RU32, rVol=%RU32\n",
     250                 pMixer->pszName, pVol->uLeft, pVol->uRight,
     251                 pMixer->VolMaster.fMuted, pMixer->VolMaster.uLeft, pMixer->VolMaster.uRight));
     252
     253    AudioMixerInvalidate(pMixer);
     254    return VINF_SUCCESS;
     255}
     256
     257/*****************************************************************************
     258 * Mixer Sink implementation.
     259 *****************************************************************************/
     260
     261int AudioMixerSinkAddStream(PAUDMIXSINK pSink, PAUDMIXSTREAM pStream)
     262{
     263    AssertPtrReturn(pSink,   VERR_INVALID_POINTER);
     264    AssertPtrReturn(pStream, VERR_INVALID_POINTER);
     265
     266    if (pSink->cStreams == UINT8_MAX) /* 255 streams per sink max. */
     267        return VERR_NO_MORE_HANDLES;
     268
     269    /** @todo Check if stream already is assigned to (another) sink. */
     270
     271    RTListAppend(&pSink->lstStreams, &pStream->Node);
     272    pSink->cStreams++;
     273
     274    LogFlowFunc(("%s: cStreams=%RU8\n", pSink->pszName, pSink->cStreams));
     275
     276    return VINF_SUCCESS;
     277}
     278
     279static PDMAUDIOSTREAMCMD audioMixerSinkToStreamCmd(AUDMIXSINKCMD enmCmd)
     280{
     281    switch (enmCmd)
     282    {
     283        case AUDMIXSINKCMD_ENABLE:   return PDMAUDIOSTREAMCMD_ENABLE;
     284        case AUDMIXSINKCMD_DISABLE:  return PDMAUDIOSTREAMCMD_DISABLE;
     285        case AUDMIXSINKCMD_PAUSE:    return PDMAUDIOSTREAMCMD_PAUSE;
     286        case AUDMIXSINKCMD_RESUME:   return PDMAUDIOSTREAMCMD_RESUME;
     287        default:                     break;
     288    }
     289
     290    AssertMsgFailed(("Unsupported sink command %ld\n", enmCmd));
     291    return PDMAUDIOSTREAMCMD_UNKNOWN;
     292}
     293
     294int AudioMixerSinkCtl(PAUDMIXSINK pSink, AUDMIXSINKCMD enmCmd)
     295{
     296    AssertPtrReturn(pSink, VERR_INVALID_POINTER);
     297
     298    PDMAUDIOSTREAMCMD enmCmdStream = audioMixerSinkToStreamCmd(enmCmd);
     299    if (enmCmdStream == PDMAUDIOSTREAMCMD_UNKNOWN)
     300        return VERR_NOT_SUPPORTED;
     301
     302    int rc = VINF_SUCCESS;
     303
     304    PAUDMIXSTREAM pStream;
     305    RTListForEach(&pSink->lstStreams, pStream, AUDMIXSTREAM, Node)
     306    {
     307        int rc2 = AudioMixerStreamCtl(pStream, enmCmdStream, AUDMIXSTRMCTL_FLAG_NONE);
     308        if (RT_SUCCESS(rc))
     309            rc = rc2;
     310        /* Keep going. Flag? */
     311    }
     312
     313    LogFlowFunc(("Sink=%s, Cmd=%ld, rc=%Rrc\n", pSink->pszName, enmCmd, rc));
     314    return rc;
     315}
     316
     317void AudioMixerSinkDestroy(PAUDMIXSINK pSink)
     318{
     319    audioMixerSinkDestroyInternal(pSink);
     320}
     321
     322static void audioMixerSinkDestroyInternal(PAUDMIXSINK pSink)
    232323{
    233324    AssertPtrReturnVoid(pSink);
     
    235326        return;
    236327
     328    LogFunc(("%s\n", pSink->pszName));
     329
     330    PAUDMIXSTREAM pStream, pStreamNext;
     331    RTListForEachSafe(&pSink->lstStreams, pStream, pStreamNext, AUDMIXSTREAM, Node)
     332    {
     333        audioMixerSinkRemoveStreamInternal(pSink, pStream);
     334        audioMixerStreamDestroyInternal(pStream);
     335    }
     336
     337    Assert(pSink->cStreams == 0);
     338
    237339    if (pSink->pszName)
    238340        RTStrFree(pSink->pszName);
     
    241343}
    242344
    243 static void audioMixerDestroyStream(PAUDMIXSTREAM pStream)
    244 {
    245     AssertPtrReturnVoid(pStream);
    246     if (!pStream)
    247         return;
    248 
    249     RTMemFree(pStream);
    250 }
    251 
    252 int AudioMixerGetDeviceFormat(PAUDIOMIXER pMixer, PPDMAUDIOSTREAMCFG pCfg)
    253 {
    254     AssertPtrReturn(pMixer, VERR_INVALID_POINTER);
    255     AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
    256 
    257     /** @todo Perform a deep copy, if needed. */
    258     *pCfg = pMixer->devFmt;
    259 
    260     return VINF_SUCCESS;
    261 }
    262 
    263 uint32_t AudioMixerGetStreamCount(PAUDIOMIXER pMixer)
    264 {
    265     AssertPtrReturn(pMixer, 0);
    266 
    267     uint32_t cStreams = 0;
    268 
    269     PAUDMIXSINK pSink;
    270     RTListForEach(&pMixer->lstSinks, pSink, AUDMIXSINK, Node)
    271         cStreams += pSink->cStreams;
    272 
    273     return cStreams;
    274 }
    275 
    276 void AudioMixerInvalidate(PAUDIOMIXER pMixer)
    277 {
    278     AssertPtrReturnVoid(pMixer);
    279 
    280     LogFlowFunc(("%s: Invalidating ...\n", pMixer->pszName));
    281 
    282     /* Propagate new master volume to all connected sinks. */
    283     PAUDMIXSINK pSink;
    284     RTListForEach(&pMixer->lstSinks, pSink, AUDMIXSINK, Node)
    285     {
    286         int rc2 = audioMixerUpdateSinkVolume(pSink, &pMixer->VolMaster);
    287         AssertRC(rc2);
    288     }
    289 }
    290 
    291 int AudioMixerProcessSinkIn(PAUDMIXSINK pSink, AUDMIXOP enmOp, void *pvBuf, uint32_t cbBuf, uint32_t *pcbProcessed)
     345PAUDMIXSTREAM AudioMixerSinkGetStream(PAUDMIXSINK pSink, uint8_t uIndex)
     346{
     347    AssertPtrReturn(pSink, NULL);
     348    AssertMsgReturn(uIndex < pSink->cStreams,
     349                    ("Index %RU8 exceeds stream count (%RU8)", uIndex, pSink->cStreams), NULL);
     350
     351    /* Slow lookup, d'oh. */
     352    PAUDMIXSTREAM pStream = RTListGetFirst(&pSink->lstStreams, AUDMIXSTREAM, Node);
     353    while (uIndex)
     354    {
     355        pStream = RTListGetNext(&pSink->lstStreams, pStream, AUDMIXSTREAM, Node);
     356        uIndex--;
     357    }
     358
     359    AssertPtr(pStream);
     360    return pStream;
     361}
     362
     363uint8_t AudioMixerSinkGetStreamCount(PAUDMIXSINK pSink)
     364{
     365    if (!pSink)
     366        return 0;
     367
     368    return pSink->cStreams;
     369}
     370
     371int AudioMixerSinkRead(PAUDMIXSINK pSink, AUDMIXOP enmOp, void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead)
    292372{
    293373    AssertPtrReturn(pSink, VERR_INVALID_POINTER);
    294374    AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
    295     AssertReturn(cbBuf, VERR_INVALID_PARAMETER);
    296     /* pcbProcessed is optional. */
     375    AssertReturn(cbBuf,    VERR_INVALID_PARAMETER);
     376    /* pcbRead is optional. */
    297377
    298378    /** @todo Handle mixing operation enmOp! */
     
    303383
    304384    int rc = VERR_NOT_FOUND;
    305     uint32_t cbProcessed = 0;
    306 
    307     LogFlowFunc(("%s: pvBuf=%p, cbBuf=%zu\n", pSink->pszName, pvBuf, cbBuf));
     385    uint32_t cbRead = 0;
    308386
    309387    PAUDMIXSTREAM pStream;
    310388    RTListForEach(&pSink->lstStreams, pStream, AUDMIXSTREAM, Node)
    311389    {
    312         if (!pStream->pConn->pfnIsActiveIn(pStream->pConn, pStream->pIn))
     390        if (!pStream->pConn->pfnIsActiveIn(pStream->pConn, pStream->InOut.pIn))
    313391            continue;
    314392
     
    318396        while (cbToRead)
    319397        {
    320             uint32_t cbRead;
     398            uint32_t cbReadStrm;
    321399            AssertPtr(pStream->pConn);
    322             rc = pStream->pConn->pfnRead(pStream->pConn, pStream->pIn,
    323                                          (uint8_t *)pvMixBuf + cbTotalRead, cbToRead, &cbRead);
     400            rc = pStream->pConn->pfnRead(pStream->pConn, pStream->InOut.pIn,
     401                                         (uint8_t *)pvMixBuf + cbTotalRead, cbToRead, &cbReadStrm);
    324402            if (   RT_FAILURE(rc)
    325                 || !cbRead)
     403                || !cbReadStrm)
    326404                break;
    327405
    328406            /** @todo Right now we only handle one stream (the last one added in fact). */
    329407
    330             AssertBreakStmt(cbRead <= cbToRead, rc = VERR_BUFFER_OVERFLOW);
    331             cbToRead -= cbRead;
    332             cbTotalRead += cbRead;
     408            AssertBreakStmt(cbReadStrm <= cbToRead, rc = VERR_BUFFER_OVERFLOW);
     409            cbToRead    -= cbReadStrm;
     410            cbTotalRead += cbReadStrm;
    333411        }
    334412
     
    336414            continue;
    337415
    338         cbProcessed = RT_MAX(cbProcessed, cbTotalRead);
     416        cbRead = RT_MAX(cbRead, cbTotalRead);
    339417    }
    340418
    341419    if (RT_SUCCESS(rc))
    342420    {
    343         memcpy(pvBuf, pvMixBuf, cbProcessed); /* @todo Use an intermediate mixing buffer per sink! */
    344 
    345         if (pcbProcessed)
    346             *pcbProcessed = cbProcessed;
     421        memcpy(pvBuf, pvMixBuf, cbRead); /* @todo Use an intermediate mixing buffer per sink! */
     422
     423        if (pcbRead)
     424            *pcbRead = cbRead;
    347425    }
    348426
    349427    RTMemFree(pvMixBuf);
    350428
    351     LogFlowFunc(("cbProcessed=%RU32, rc=%Rrc\n", cbProcessed, rc));
     429    Log3Func(("%s: cbRead=%RU32, rc=%Rrc\n", pSink->pszName, cbRead, rc));
    352430    return rc;
    353431}
    354432
    355 int AudioMixerProcessSinkOut(PAUDMIXSINK pSink, AUDMIXOP enmOp, const void *pvBuf, uint32_t cbBuf, uint32_t *pcbProcessed)
    356 {
    357     return VERR_NOT_IMPLEMENTED;
    358 }
    359 
    360 void AudioMixerRemoveSink(PAUDIOMIXER pMixer, PAUDMIXSINK pSink)
    361 {
    362     AssertPtrReturnVoid(pMixer);
    363     if (!pSink)
    364         return;
    365 
    366     PAUDMIXSTREAM pStream, pStreamNext;
    367     RTListForEachSafe(&pSink->lstStreams, pStream, pStreamNext, AUDMIXSTREAM, Node)
    368         AudioMixerRemoveStream(pSink, pStream);
    369 
    370     Assert(pSink->cStreams == 0);
    371 
    372     RTListNodeRemove(&pSink->Node);
    373     Assert(pMixer->cSinks);
    374     pMixer->cSinks--;
    375 
    376     LogFlowFunc(("%s: pSink=%s, cSinks=%RU8\n",
    377                  pMixer->pszName, pSink->pszName, pMixer->cSinks));
    378 
    379     audioMixerDestroySink(pSink);
    380 }
    381 
    382 void AudioMixerRemoveStream(PAUDMIXSINK pSink, PAUDMIXSTREAM pStream)
     433static void audioMixerSinkRemoveStreamInternal(PAUDMIXSINK pSink, PAUDMIXSTREAM pStream)
    383434{
    384435    AssertPtrReturnVoid(pSink);
     
    386437        return;
    387438
     439    /** @todo Check if pStream is part of pSink. */
     440
    388441    Assert(pSink->cStreams);
    389     RTListNodeRemove(&pStream->Node);
    390     pSink->cStreams--;
    391442
    392443#ifdef DEBUG
    393444    const char *pszStream = pSink->enmDir == AUDMIXSINKDIR_INPUT
    394                           ? pStream->pIn->MixBuf.pszName : pStream->pOut->MixBuf.pszName;
    395 
    396     LogFlowFunc(("%s: pStream=%s, cStreams=%RU8\n",
     445                          ? pStream->InOut.pIn->MixBuf.pszName : pStream->InOut.pOut->MixBuf.pszName;
     446
     447    LogFlowFunc(("%s: (Stream = %s), cStreams=%RU8\n",
    397448                 pSink->pszName, pszStream ? pszStream : "<Unnamed>", pSink->cStreams));
    398449#endif
    399450
    400     /* Decrease the reference count again. */
    401     switch (pSink->enmDir)
    402     {
    403         case AUDMIXSINKDIR_INPUT:
    404         {
    405             Assert(pStream->pIn->State.cRefs);
    406             pStream->pIn->State.cRefs--;
    407             break;
    408         }
    409 
    410         case AUDMIXSINKDIR_OUTPUT:
    411         {
    412             Assert(pStream->pOut->State.cRefs);
    413             pStream->pOut->State.cRefs--;
    414             break;
    415         }
    416 
    417         default:
    418             AssertMsgFailed(("Not implemented\n"));
    419             break;
    420     }
    421 
    422     audioMixerDestroyStream(pStream);
    423 }
    424 
    425 int AudioMixerSetDeviceFormat(PAUDIOMIXER pMixer, PPDMAUDIOSTREAMCFG pCfg)
    426 {
    427     AssertPtrReturn(pMixer, VERR_INVALID_POINTER);
    428     AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
    429 
    430     /** @todo Perform a deep copy, if needed. */
    431     pMixer->devFmt = *pCfg;
     451    /* Remove stream from sink. */
     452    RTListNodeRemove(&pStream->Node);
     453
     454    Assert(pSink->cStreams);
     455    pSink->cStreams--;
     456}
     457
     458void AudioMixerSinkRemoveStream(PAUDMIXSINK pSink, PAUDMIXSTREAM pStream)
     459{
     460    audioMixerSinkRemoveStreamInternal(pSink, pStream);
     461}
     462
     463/**
     464 * Removes all attached streams from a given sink.
     465 *
     466 * @param pSink         Sink to remove attached streams from.
     467 */
     468void AudioMixerSinkRemoveAllStreams(PAUDMIXSINK pSink)
     469{
     470    if (!pSink)
     471        return;
     472
     473    LogFunc(("%s\n", pSink->pszName));
     474
     475    PAUDMIXSTREAM pStream, pStreamNext;
     476    RTListForEachSafe(&pSink->lstStreams, pStream, pStreamNext, AUDMIXSTREAM, Node)
     477        audioMixerSinkRemoveStreamInternal(pSink, pStream);
     478
     479    Assert(pSink->cStreams == 0);
     480}
     481
     482int AudioMixerSinkSetFormat(PAUDMIXSINK pSink, PPDMPCMPROPS pPCMProps)
     483{
     484    AssertPtrReturn(pSink,     VERR_INVALID_POINTER);
     485    AssertPtrReturn(pPCMProps, VERR_INVALID_POINTER);
     486
     487    memcpy(&pSink->PCMProps, pPCMProps, sizeof(PDMPCMPROPS));
     488
     489    PAUDMIXSTREAM pStream;
     490    RTListForEach(&pSink->lstStreams, pStream, AUDMIXSTREAM, Node)
     491    {
     492        /** @todo Invalidate mix buffers! */
     493    }
    432494
    433495    return VINF_SUCCESS;
    434496}
    435497
    436 static int audioMixerUpdateSinkVolume(PAUDMIXSINK pSink, const PPDMAUDIOVOLUME pVolMaster)
     498/**
     499 * Set the volume of an individual sink.
     500 *
     501 * @returns IPRT status code.
     502 * @param   pSink           Sink to set volume for.
     503 * @param   pVol            Volume to set.
     504 */
     505int AudioMixerSinkSetVolume(PAUDMIXSINK pSink, PPDMAUDIOVOLUME pVol)
     506{
     507    AssertPtrReturn(pSink, VERR_INVALID_POINTER);
     508    AssertPtrReturn(pVol,  VERR_INVALID_POINTER);
     509    AssertPtr(pSink->pParent);
     510
     511    LogFlowFunc(("%s: fMuted=%RTbool, lVol=%RU32, rVol=%RU32\n", pSink->pszName, pVol->fMuted, pVol->uLeft, pVol->uRight));
     512
     513    pSink->Volume = *pVol;
     514
     515    return audioMixerSinkUpdateVolume(pSink, &pSink->pParent->VolMaster);
     516}
     517
     518int AudioMixerSinkUpdate(PAUDMIXSINK pSink)
     519{
     520    AssertPtrReturn(pSink, VERR_INVALID_POINTER);
     521
     522    PAUDMIXSTREAM pStream;
     523    RTListForEach(&pSink->lstStreams, pStream, AUDMIXSTREAM, Node)
     524    {
     525        uint32_t cbIn, cbOut;
     526        uint32_t cSamplesLive;
     527        int rc2 = pStream->pConn->pfnQueryStatus(pStream->pConn,
     528                                                 &cbIn, &cbOut, &cSamplesLive);
     529#ifdef DEBUG
     530        if (   cbIn
     531            || cbOut
     532            || cSamplesLive)
     533        {
     534            Log3Func(("cbIn=%RU32, cbOut=%RU32, cSamplesLive=%RU32, rc2=%Rrc\n", cbIn, cbOut, cSamplesLive, rc2));
     535        }
     536#endif
     537        if (pSink->enmDir == AUDMIXSINKDIR_OUTPUT)
     538        {
     539            rc2 = pStream->pConn->pfnPlayOut(pStream->pConn, NULL /* pcSamplesPlayed */);
     540            if (RT_FAILURE(rc2))
     541                Log3Func(("rc2=%Rrc\n", rc2));
     542        }
     543        else if (pSink->enmDir == AUDMIXSINKDIR_INPUT)
     544        {
     545            //int rc2 = pStream->pConn->pfnCaptureIn(pStream->pConn, NULL /* pcSamplesCaptured */);
     546            //Log3Func(("rc2=%Rrc\n", rc2));
     547        }
     548        else
     549            AssertMsgFailed(("Direction not implemented\n"));
     550    }
     551
     552    return VINF_SUCCESS;
     553}
     554
     555static int audioMixerSinkUpdateVolume(PAUDMIXSINK pSink, const PPDMAUDIOVOLUME pVolMaster)
    437556{
    438557    AssertPtrReturn(pSink,      VERR_INVALID_POINTER);
     
    461580    {
    462581        if (fOut)
    463             AudioMixBufSetVolume(&pStream->pOut->MixBuf, &volSink);
     582            AudioMixBufSetVolume(&pStream->InOut.pOut->MixBuf, &volSink);
    464583        else
    465             AudioMixBufSetVolume(&pStream->pIn->MixBuf,  &volSink);
     584            AudioMixBufSetVolume(&pStream->InOut.pIn->MixBuf,  &volSink);
    466585    }
    467586
     
    469588}
    470589
    471 /** Set the master volume of the mixer. */
    472 int AudioMixerSetMasterVolume(PAUDIOMIXER pMixer, PPDMAUDIOVOLUME pVol)
    473 {
    474     AssertPtrReturn(pMixer, VERR_INVALID_POINTER);
    475     AssertPtrReturn(pVol,   VERR_INVALID_POINTER);
    476 
    477     pMixer->VolMaster = *pVol;
    478 
    479     LogFlowFunc(("%s: lVol=%RU32, rVol=%RU32 => fMuted=%RTbool, lVol=%RU32, rVol=%RU32\n",
    480                  pMixer->pszName, pVol->uLeft, pVol->uRight,
    481                  pMixer->VolMaster.fMuted, pMixer->VolMaster.uLeft, pMixer->VolMaster.uRight));
    482 
    483     AudioMixerInvalidate(pMixer);
     590int AudioMixerSinkWrite(PAUDMIXSINK pSink, AUDMIXOP enmOp, const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten)
     591{
     592    AssertPtrReturn(pSink, VERR_INVALID_POINTER);
     593    /* pcbWritten is optional. */
     594
     595    if (!pvBuf || !cbBuf)
     596    {
     597        if (pcbWritten)
     598            *pcbWritten = 0;
     599        return VINF_SUCCESS;
     600    }
     601
     602    uint32_t cbProcessed = 0;
     603
     604    PAUDMIXSTREAM pStream;
     605    RTListForEach(&pSink->lstStreams, pStream, AUDMIXSTREAM, Node)
     606    {
     607        int rc2 = pStream->pConn->pfnWrite(pStream->pConn, pStream->InOut.pOut, pvBuf, cbBuf, &cbProcessed);
     608        if (   RT_FAILURE(rc2)
     609            || cbProcessed < cbBuf)
     610        {
     611            LogFlowFunc(("rc=%Rrc, cbBuf=%RU32, cbProcessed=%RU32\n", rc2, cbBuf, cbProcessed));
     612        }
     613    }
     614
     615    if (pcbWritten)
     616        *pcbWritten = cbBuf; /* Always report back a complete write for now. */
     617
    484618    return VINF_SUCCESS;
    485619}
    486620
    487 /** Set the volume of an individual sink. */
    488 int AudioMixerSetSinkVolume(PAUDMIXSINK pSink, PPDMAUDIOVOLUME pVol)
    489 {
    490     AssertPtrReturn(pSink, VERR_INVALID_POINTER);
    491     AssertPtrReturn(pVol,  VERR_INVALID_POINTER);
    492     AssertPtr(pSink->pParent);
    493 
    494     LogFlowFunc(("%s: fMuted=%RTbool, lVol=%RU32, rVol=%RU32\n", pSink->pszName, pVol->fMuted, pVol->uLeft, pVol->uRight));
    495 
    496     pSink->Volume = *pVol;
    497 
    498     return audioMixerUpdateSinkVolume(pSink, &pSink->pParent->VolMaster);
    499 }
    500 
    501 void AudioMixerDebug(PAUDIOMIXER pMixer, PCDBGFINFOHLP pHlp, const char *pszArgs)
    502 {
    503     PAUDMIXSINK pSink;
    504     unsigned    iSink = 0;
    505 
    506     pHlp->pfnPrintf(pHlp, "[Master] %s: lVol=%u, rVol=%u, fMuted=%RTbool\n", pMixer->pszName,
    507                     pMixer->VolMaster.uLeft, pMixer->VolMaster.uRight, pMixer->VolMaster.fMuted);
    508 
    509     RTListForEach(&pMixer->lstSinks, pSink, AUDMIXSINK, Node)
    510     {
    511         pHlp->pfnPrintf(pHlp, "[Sink %u] %s: lVol=%u, rVol=%u, fMuted=%RTbool\n", iSink, pSink->pszName,
    512                         pSink->Volume.uLeft, pSink->Volume.uRight, pSink->Volume.fMuted);
    513         ++iSink;
    514     }
    515 }
     621/*****************************************************************************
     622 * Mixer Stream implementation.
     623 *****************************************************************************/
     624
     625int AudioMixerStreamCtl(PAUDMIXSTREAM pStream, PDMAUDIOSTREAMCMD enmCmd, uint32_t fCtl)
     626{
     627    AssertPtrReturn(pStream, VERR_INVALID_POINTER);
     628    /** @todo Validate fCtl. */
     629
     630    int rc;
     631    switch (pStream->enmDir)
     632    {
     633        case PDMAUDIODIR_IN:
     634        {
     635            if (   enmCmd == PDMAUDIOSTREAMCMD_ENABLE
     636                || enmCmd == PDMAUDIOSTREAMCMD_DISABLE)
     637            {
     638                rc = pStream->pConn->pfnEnableIn(pStream->pConn, pStream->InOut.pIn,
     639                                                 enmCmd == PDMAUDIOSTREAMCMD_ENABLE);
     640            }
     641            else
     642                AssertFailed();
     643            break;
     644        }
     645
     646        case PDMAUDIODIR_OUT:
     647        {
     648            if (   enmCmd == PDMAUDIOSTREAMCMD_ENABLE
     649                || enmCmd == PDMAUDIOSTREAMCMD_DISABLE)
     650            {
     651                rc = pStream->pConn->pfnEnableOut(pStream->pConn, pStream->InOut.pOut,
     652                                                  enmCmd == PDMAUDIOSTREAMCMD_ENABLE);
     653            }
     654            else
     655                AssertFailed();
     656            break;
     657        }
     658
     659        default:
     660            AssertMsgFailed(("Not implemented\n"));
     661            break;
     662    }
     663
     664    return rc;
     665}
     666
     667int AudioMixerStreamCreate(PPDMIAUDIOCONNECTOR pConn, PPDMAUDIOSTREAMCFG pCfg, uint32_t fFlags, PAUDMIXSTREAM *ppStream)
     668{
     669    AssertPtrReturn(pConn, VERR_INVALID_POINTER);
     670    AssertPtrReturn(pCfg,  VERR_INVALID_POINTER);
     671    /** @todo Validate fFlags. */
     672    /* ppStream is optional. */
     673
     674    PAUDMIXSTREAM pMixStream = (PAUDMIXSTREAM)RTMemAllocZ(sizeof(AUDMIXSTREAM));
     675    if (!pMixStream)
     676        return VERR_NO_MEMORY;
     677
     678    pMixStream->pszName = RTStrDup(pCfg->szName);
     679    if (!pMixStream->pszName)
     680    {
     681        RTMemFree(pMixStream);
     682        return VERR_NO_MEMORY;
     683    }
     684
     685    int rc;
     686    if (pCfg->enmDir == PDMAUDIODIR_IN)
     687    {
     688        PPDMAUDIOGSTSTRMIN pGstStrm;
     689        rc = pConn->pfnCreateIn(pConn, pCfg, &pGstStrm);
     690        if (RT_SUCCESS(rc))
     691        {
     692            pMixStream->InOut.pIn = pGstStrm;
     693
     694            /* Increase the stream's reference count to let others know
     695             * we're reyling on it to be around now. */
     696            pConn->pfnAddRefIn(pConn, pGstStrm);
     697        }
     698    }
     699    else if (pCfg->enmDir == PDMAUDIODIR_OUT)
     700    {
     701        PPDMAUDIOGSTSTRMOUT pGstStrm;
     702        rc = pConn->pfnCreateOut(pConn, pCfg, &pGstStrm);
     703        if (RT_SUCCESS(rc))
     704        {
     705            pMixStream->InOut.pOut = pGstStrm;
     706
     707            /* Increase the stream's reference count to let others know
     708             * we're reyling on it to be around now. */
     709            pConn->pfnAddRefOut(pConn, pGstStrm);
     710        }
     711    }
     712    else
     713        rc = VERR_NOT_SUPPORTED;
     714
     715    if (RT_SUCCESS(rc))
     716    {
     717        pMixStream->fFlags = fFlags;
     718        pMixStream->enmDir = pCfg->enmDir;
     719        pMixStream->pConn  = pConn;
     720
     721        if (ppStream)
     722            *ppStream = pMixStream;
     723    }
     724    else if (pMixStream)
     725    {
     726        RTStrFree(pMixStream->pszName);
     727        pMixStream->pszName = NULL;
     728
     729        RTMemFree(pMixStream);
     730        pMixStream = NULL;
     731    }
     732
     733    return rc;
     734}
     735
     736static void audioMixerStreamDestroyInternal(PAUDMIXSTREAM pStream)
     737{
     738    if (!pStream)
     739        return;
     740
     741    LogFunc(("%s\n", pStream->pszName));
     742
     743    if (pStream->pConn) /* Stream has a connector interface present? */
     744    {
     745        if (   pStream->enmDir == PDMAUDIODIR_IN
     746            && pStream->pConn->pfnDestroyIn)
     747        {
     748            if (pStream->InOut.pIn)
     749            {
     750                pStream->pConn->pfnReleaseIn(pStream->pConn, pStream->InOut.pIn);
     751                pStream->pConn->pfnDestroyIn(pStream->pConn, pStream->InOut.pIn);
     752            }
     753        }
     754        else if (   pStream->enmDir == PDMAUDIODIR_OUT
     755                 && pStream->pConn->pfnDestroyOut)
     756        {
     757            if (pStream->InOut.pOut)
     758            {
     759                pStream->pConn->pfnReleaseOut(pStream->pConn, pStream->InOut.pOut);
     760                pStream->pConn->pfnDestroyOut(pStream->pConn, pStream->InOut.pOut);
     761            }
     762        }
     763        else
     764            AssertFailed();
     765    }
     766
     767    audioMixerStreamFree(pStream);
     768}
     769
     770void AudioMixerStreamDestroy(PAUDMIXSTREAM pStream)
     771{
     772    audioMixerStreamDestroyInternal(pStream);
     773}
     774
     775static void audioMixerStreamFree(PAUDMIXSTREAM pStream)
     776{
     777    if (pStream)
     778    {
     779        LogFunc(("%s\n", pStream->pszName));
     780
     781        if (pStream->pszName)
     782        {
     783            RTStrFree(pStream->pszName);
     784            pStream->pszName = NULL;
     785        }
     786
     787        RTMemFree(pStream);
     788        pStream = NULL;
     789    }
     790}
     791
     792bool AudioMixerStreamIsActive(PAUDMIXSTREAM pStream)
     793{
     794    if (!pStream)
     795        return false;
     796
     797    bool fIsValid;
     798    switch (pStream->enmDir)
     799    {
     800        case PDMAUDIODIR_IN:
     801        {
     802            fIsValid = pStream->pConn->pfnIsActiveIn(pStream->pConn, pStream->InOut.pIn);
     803            break;
     804        }
     805
     806        case PDMAUDIODIR_OUT:
     807        {
     808            fIsValid = pStream->pConn->pfnIsActiveOut(pStream->pConn, pStream->InOut.pOut);
     809            break;
     810        }
     811
     812        default:
     813            fIsValid = false;
     814            AssertMsgFailed(("Not implemented\n"));
     815            break;
     816    }
     817
     818    return fIsValid;
     819}
     820
     821bool AudioMixerStreamIsValid(PAUDMIXSTREAM pStream)
     822{
     823    if (!pStream)
     824        return false;
     825
     826    bool fIsValid;
     827    switch (pStream->enmDir)
     828    {
     829        case PDMAUDIODIR_IN:
     830        {
     831            fIsValid = pStream->pConn->pfnIsValidIn(pStream->pConn, pStream->InOut.pIn);
     832            break;
     833        }
     834
     835        case PDMAUDIODIR_OUT:
     836        {
     837            fIsValid = pStream->pConn->pfnIsValidOut(pStream->pConn, pStream->InOut.pOut);
     838            break;
     839        }
     840
     841        default:
     842            fIsValid = false;
     843            AssertMsgFailed(("Not implemented\n"));
     844            break;
     845    }
     846
     847    return fIsValid;
     848}
     849
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