VirtualBox

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


Ignore:
Timestamp:
May 28, 2021 8:52:58 PM (4 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
144722
Message:

AudioMixer: More cleanups. bugref:9890

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

Legend:

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

    r89354 r89371  
    922922
    923923/**
    924  * Destroys (uninitializes) a mixing buffer.
     924 * Terminates (uninitializes) a mixing buffer.
    925925 *
    926926 * @param   pMixBuf     The mixing buffer.  Uninitialized mixer buffers will be
    927927 *                      quietly ignored.  As will NULL.
    928928 */
    929 void AudioMixBufDestroy(PAUDIOMIXBUF pMixBuf)
     929void AudioMixBufTerm(PAUDIOMIXBUF pMixBuf)
    930930{
    931931    if (!pMixBuf)
  • trunk/src/VBox/Devices/Audio/AudioMixBuffer.h

    r89352 r89371  
    182182
    183183int         AudioMixBufInit(PAUDIOMIXBUF pMixBuf, const char *pszName, PCPDMAUDIOPCMPROPS pProps, uint32_t cFrames);
    184 void        AudioMixBufDestroy(PAUDIOMIXBUF pMixBuf);
     184void        AudioMixBufTerm(PAUDIOMIXBUF pMixBuf);
    185185void        AudioMixBufDrop(PAUDIOMIXBUF pMixBuf);
    186186void        AudioMixBufSetVolume(PAUDIOMIXBUF pMixBuf, PCPDMAUDIOVOLUME pVol);
  • trunk/src/VBox/Devices/Audio/AudioMixer.cpp

    r89357 r89371  
    104104static void audioMixerSinkDestroyInternal(PAUDMIXSINK pSink, PPDMDEVINS pDevIns);
    105105static int audioMixerSinkUpdateVolume(PAUDMIXSINK pSink, PCPDMAUDIOVOLUME pVolMaster);
    106 static void audioMixerSinkRemoveAllStreamsInternal(PAUDMIXSINK pSink);
    107106static int audioMixerSinkRemoveStreamInternal(PAUDMIXSINK pSink, PAUDMIXSTREAM pStream);
    108 static void audioMixerSinkReset(PAUDMIXSINK pSink);
     107static void audioMixerSinkResetInternal(PAUDMIXSINK pSink);
    109108
    110109static int audioMixerStreamCtlInternal(PAUDMIXSTREAM pMixStream, PDMAUDIOSTREAMCMD enmCmd);
     
    234233    RTListForEachSafe(&pMixer->lstSinks, pSink, pSinkNext, AUDMIXSINK, Node)
    235234    {
     235        audioMixerRemoveSinkInternal(pMixer, pSink);
    236236        audioMixerSinkDestroyInternal(pSink, pDevIns);
    237         audioMixerRemoveSinkInternal(pMixer, pSink);
    238         RTMemFree(pSink);
    239237    }
    240238    Assert(pMixer->cSinks == 0);
     
    454452
    455453/**
    456  * Adds an audio stream to a specific audio sink.
    457  *
    458  * @returns VBox status code.
    459  * @param   pSink               Sink to add audio stream to.
    460  * @param   pStream             Stream to add.
    461  */
    462 int AudioMixerSinkAddStream(PAUDMIXSINK pSink, PAUDMIXSTREAM pStream)
    463 {
    464     LogFlowFuncEnter();
    465     AssertPtrReturn(pSink,   VERR_INVALID_POINTER);
    466     Assert(pSink->uMagic == AUDMIXSINK_MAGIC);
    467     AssertPtrReturn(pStream, VERR_INVALID_POINTER);
    468     Assert(pStream->uMagic == AUDMIXSTREAM_MAGIC);
    469     AssertPtrReturn(pStream->pConn, VERR_AUDIO_STREAM_NOT_READY);
    470     AssertReturn(pStream->pSink == NULL, VERR_ALREADY_EXISTS);
    471 
    472     int rc = RTCritSectEnter(&pSink->CritSect);
    473     AssertRCReturn(rc, rc);
    474 
    475     AssertLogRelMsgReturnStmt(pSink->cStreams < UINT8_MAX, ("too many streams!\n"), RTCritSectLeave(&pSink->CritSect),
    476                               VERR_TOO_MANY_OPEN_FILES);
    477 
    478     /*
    479      * If the sink is running and not in pending disable mode, make sure that
    480      * the added stream also is enabled.   Ignore any failure to enable it.
    481      */
    482     if (    (pSink->fStatus & AUDMIXSINK_STS_RUNNING)
    483         && !(pSink->fStatus & AUDMIXSINK_STS_DRAINING))
    484     {
    485         audioMixerStreamCtlInternal(pStream, PDMAUDIOSTREAMCMD_ENABLE);
    486     }
    487 
    488     /* Save pointer to sink the stream is attached to. */
    489     pStream->pSink = pSink;
    490 
    491     /* Append stream to sink's list. */
    492     RTListAppend(&pSink->lstStreams, &pStream->Node);
    493     pSink->cStreams++;
    494 
    495     LogFlowFunc(("[%s] cStreams=%RU8, rc=%Rrc\n", pSink->pszName, pSink->cStreams, rc));
    496     RTCritSectLeave(&pSink->CritSect);
    497     return rc;
    498 }
    499 
    500 /**
    501  * Creates an audio mixer stream.
    502  *
    503  * @returns VBox status code.
    504  * @param   pSink       Sink to use for creating the stream.
    505  * @param   pConn       Audio connector interface to use.
    506  * @param   pCfg        Audio stream configuration to use.  This may be modified
    507  *                      in some unspecified way (see
    508  *                      PDMIAUDIOCONNECTOR::pfnStreamCreate).
    509  * @param   pDevIns     The device instance to register statistics with.
    510  * @param   ppStream    Pointer which receives the newly created audio stream.
    511  */
    512 int AudioMixerSinkCreateStream(PAUDMIXSINK pSink, PPDMIAUDIOCONNECTOR pConn, PPDMAUDIOSTREAMCFG pCfg,
    513                                PPDMDEVINS pDevIns, PAUDMIXSTREAM *ppStream)
    514 {
    515     AssertPtrReturn(pSink, VERR_INVALID_POINTER);
    516     Assert(pSink->uMagic == AUDMIXSINK_MAGIC);
    517     AssertPtrReturn(pConn, VERR_INVALID_POINTER);
    518     AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
    519     AssertPtrNullReturn(ppStream, VERR_INVALID_POINTER);
    520     Assert(pSink->AIO.pDevIns == pDevIns); RT_NOREF(pDevIns); /* we'll probably be adding more statistics */
    521     AssertReturn(pCfg->enmDir == pSink->enmDir, VERR_MISMATCH);
    522 
    523     /*
    524      * Check status and get the host driver config.
    525      */
    526     if (pConn->pfnGetStatus(pConn, PDMAUDIODIR_DUPLEX) == PDMAUDIOBACKENDSTS_NOT_ATTACHED)
    527         return VERR_AUDIO_BACKEND_NOT_ATTACHED;
    528 
    529     PDMAUDIOBACKENDCFG BackendCfg;
    530     int rc = pConn->pfnGetConfig(pConn, &BackendCfg);
    531     AssertRCReturn(rc, rc);
    532 
    533     /*
    534      * Allocate the instance.
    535      */
    536     PAUDMIXSTREAM pMixStream = (PAUDMIXSTREAM)RTMemAllocZ(sizeof(AUDMIXSTREAM));
    537     AssertReturn(pMixStream, VERR_NO_MEMORY);
    538 
    539     /* Assign the backend's name to the mixer stream's name for easier identification in the (release) log. */
    540     pMixStream->pszName = RTStrAPrintf2("[%s] %s", pCfg->szName, BackendCfg.szName);
    541     pMixStream->pszStatPrefix = RTStrAPrintf2("MixerSink-%s/%s/", pSink->pszName, BackendCfg.szName);
    542     if (pMixStream->pszName && pMixStream->pszStatPrefix)
    543     {
    544         rc = RTCritSectInit(&pMixStream->CritSect);
    545         if (RT_SUCCESS(rc))
    546         {
    547             /*
    548              * Lock the sink so we can safely get it's properties and call
    549              * down into the audio driver to create that end of the stream.
    550              */
    551             rc = RTCritSectEnter(&pSink->CritSect);
    552             AssertRC(rc);
    553             if (RT_SUCCESS(rc))
    554             {
    555                 LogFlowFunc(("[%s] (enmDir=%ld, %u bits, %RU8 channels, %RU32Hz)\n", pSink->pszName, pCfg->enmDir,
    556                              PDMAudioPropsSampleBits(&pCfg->Props), PDMAudioPropsChannels(&pCfg->Props), pCfg->Props.uHz));
    557 
    558                 /*
    559                  * Initialize the host-side configuration for the stream to be created,
    560                  * this is the sink format & direction with the src/dir, layout, name
    561                  * and device specific config copied from the guest side config (pCfg).
    562                  */
    563                 AssertMsg(AudioHlpPcmPropsAreValid(&pSink->PCMProps),
    564                           ("%s: Does not (yet) have a format set when it must\n", pSink->pszName));
    565 
    566                 PDMAUDIOSTREAMCFG CfgHost;
    567                 rc = PDMAudioStrmCfgInitWithProps(&CfgHost, &pSink->PCMProps);
    568                 AssertRC(rc); /* cannot fail */
    569                 CfgHost.enmDir    = pSink->enmDir;
    570                 CfgHost.enmPath   = pCfg->enmPath;
    571                 CfgHost.enmLayout = pCfg->enmLayout;
    572                 CfgHost.Device    = pCfg->Device;
    573                 RTStrCopy(CfgHost.szName, sizeof(CfgHost.szName), pCfg->szName);
    574 
    575                 /*
    576                  * Create the stream.
    577                  *
    578                  * Output streams are not using any mixing buffers in DrvAudio.  This will
    579                  * become the norm after we move the input mixing here and convert DevSB16
    580                  * to use this mixer code too.
    581                  */
    582                 PPDMAUDIOSTREAM pStream;
    583                 rc = pConn->pfnStreamCreate(pConn, 0 /*fFlags*/, &CfgHost, pCfg, &pStream);
    584                 if (RT_SUCCESS(rc))
    585                 {
    586                     pMixStream->cFramesBackendBuffer = CfgHost.Backend.cFramesBufferSize;
    587 
    588                     /* Set up the mixing buffer conversion state. */
    589                     if (pSink->enmDir == PDMAUDIODIR_IN)
    590                         rc = AudioMixBufInitWriteState(&pSink->MixBuf, &pMixStream->WriteState, &pStream->Props);
    591                     else
    592                         rc = AudioMixBufInitPeekState(&pSink->MixBuf, &pMixStream->PeekState, &pStream->Props);
    593                     if (RT_SUCCESS(rc))
    594                     {
    595                         /* Save the audio stream pointer to this mixing stream. */
    596                         pMixStream->pStream = pStream;
    597 
    598                         /* Increase the stream's reference count to let others know
    599                          * we're relying on it to be around now. */
    600                         pConn->pfnStreamRetain(pConn, pStream);
    601                         pMixStream->pConn  = pConn;
    602                         pMixStream->uMagic = AUDMIXSTREAM_MAGIC;
    603 
    604                         RTCritSectLeave(&pSink->CritSect);
    605 
    606                         if (ppStream)
    607                             *ppStream = pMixStream;
    608                         return VINF_SUCCESS;
    609                     }
    610 
    611                     rc = pConn->pfnStreamDestroy(pConn, pStream, true /*fImmediate*/);
    612                 }
    613 
    614                 /*
    615                  * Failed.  Tear down the stream.
    616                  */
    617                 int rc2 = RTCritSectLeave(&pSink->CritSect);
    618                 AssertRC(rc2);
    619             }
    620             RTCritSectDelete(&pMixStream->CritSect);
    621         }
    622     }
    623     else
    624         rc = VERR_NO_STR_MEMORY;
    625 
    626     RTStrFree(pMixStream->pszStatPrefix);
    627     pMixStream->pszStatPrefix = NULL;
    628     RTStrFree(pMixStream->pszName);
    629     pMixStream->pszName = NULL;
    630     RTMemFree(pMixStream);
    631     return rc;
    632 }
    633 
    634 
    635 /**
    636454 * Starts playback/capturing on the mixer sink.
    637455 *
     
    667485            audioMixerStreamCtlInternal(pStream, PDMAUDIOSTREAMCMD_DISABLE);
    668486        }
    669         audioMixerSinkReset(pSink);
     487        audioMixerSinkResetInternal(pSink);
    670488    }
    671489
     
    803621                        audioMixerStreamCtlInternal(pStream, PDMAUDIOSTREAMCMD_DISABLE);
    804622                    }
    805                     audioMixerSinkReset(pSink);
     623                    audioMixerSinkResetInternal(pSink);
    806624                }
    807625            }
     
    823641                audioMixerStreamCtlInternal(pStream, PDMAUDIOSTREAMCMD_DISABLE);
    824642            }
    825             audioMixerSinkReset(pSink);
     643            audioMixerSinkResetInternal(pSink);
    826644        }
    827645    }
     
    836654
    837655/**
    838  * Destroys a mixer sink.
     656 * Destroys and frees a mixer sink.
    839657 *
    840658 * Worker for AudioMixerSinkDestroy(), AudioMixerCreateSink() and
     
    850668    LogFunc(("%s\n", pSink->pszName));
    851669
     670    /*
     671     * Invalidate the sink instance.
     672     */
    852673    Assert(pSink->uMagic == AUDMIXSINK_MAGIC);
    853674    pSink->uMagic = AUDMIXSINK_MAGIC_DEAD;
    854675
     676    /*
     677     * Destroy all streams.
     678     */
    855679    PAUDMIXSTREAM pStream, pStreamNext;
    856680    RTListForEachSafe(&pSink->lstStreams, pStream, pStreamNext, AUDMIXSTREAM, Node)
    857681    {
    858682        audioMixerSinkRemoveStreamInternal(pSink, pStream);
    859         audioMixerStreamDestroyInternal(pStream, pDevIns, true /*fImmediate*/); /* (Unlike the other two, this frees the stream structure.) */
    860     }
    861 
    862     /** @todo r=bird: this looks wrong for the AudioMixerSinkDestroy case ...   */
    863     if (   pSink->pParent
    864         && pSink->pParent->fFlags & AUDMIXER_FLAGS_DEBUG)
     683        audioMixerStreamDestroyInternal(pStream, pDevIns, true /*fImmediate*/);
     684    }
     685
     686    /*
     687     * Destroy debug file and statistics.
     688     */
     689    if (!pSink->Dbg.pFile)
     690    { /* likely */ }
     691    else
    865692    {
    866693        AudioHlpFileDestroy(pSink->Dbg.pFile);
     
    872699    PDMDevHlpSTAMDeregisterByPrefix(pDevIns, szPrefix);
    873700
    874     /* Shutdown the AIO thread if started: */
     701    /*
     702     * Shutdown the AIO thread if started:
     703     */
    875704    ASMAtomicWriteBool(&pSink->AIO.fShutdown, true);
    876705    if (pSink->AIO.hEvent != NIL_RTSEMEVENT)
     
    893722    }
    894723
    895     AudioMixBufDestroy(&pSink->MixBuf);
     724    /*
     725     * Mixing buffer, critsect and the structure itself.
     726     */
     727    AudioMixBufTerm(&pSink->MixBuf);
    896728    RTCritSectDelete(&pSink->CritSect);
     729    RTMemFree(pSink);
    897730}
    898731
     
    901734 * Destroys a mixer sink and removes it from the attached mixer (if any).
    902735 *
    903  * @param   pSink       Mixer sink to destroy.
     736 * @param   pSink       Mixer sink to destroy.  NULL is ignored.
    904737 * @param   pDevIns     The device instance that statistics are registered with.
    905738 */
     
    908741    if (!pSink)
    909742        return;
     743    AssertReturnVoid(pSink->uMagic == AUDMIXSINK_MAGIC);
    910744
    911745    /*
     
    930764        AssertFailed();
    931765
     766    /*
     767     * Actually destroy it.
     768     */
    932769    audioMixerSinkDestroyInternal(pSink, pDevIns);
    933 
    934     RTMemFree(pSink);
    935     pSink = NULL;
    936 }
    937 
    938 /**
    939  * Returns the amount of bytes ready to be read from a sink since the last call
    940  * to AudioMixerSinkUpdate().
    941  *
    942  * @returns Amount of bytes ready to be read from the sink.
    943  * @param   pSink               Sink to return number of available bytes for.
     770}
     771
     772
     773/**
     774 * Get the number of bytes that can be read from the sink.
     775 *
     776 * @returns Number of bytes.
     777 * @param   pSink   The mixer sink.
     778 *
     779 * @note    Only applicable to input sinks, will assert and return zero for
     780 *          other sink directions.
    944781 */
    945782uint32_t AudioMixerSinkGetReadable(PAUDMIXSINK pSink)
    946783{
    947784    AssertPtrReturn(pSink, 0);
    948     Assert(pSink->uMagic == AUDMIXSINK_MAGIC);
    949     AssertMsg(pSink->enmDir == PDMAUDIODIR_IN, ("%s: Can't read from a non-input sink\n", pSink->pszName));
     785    AssertReturn(pSink->uMagic == AUDMIXSINK_MAGIC, 0);
     786    AssertMsgReturn(pSink->enmDir == PDMAUDIODIR_IN, ("%s: Can't read from a non-input sink\n", pSink->pszName), 0);
    950787
    951788    int rc = RTCritSectEnter(&pSink->CritSect);
     
    953790
    954791    uint32_t cbReadable = 0;
    955 
    956792    if (pSink->fStatus & AUDMIXSINK_STS_RUNNING)
    957     {
    958         uint32_t const cFrames = AudioMixBufUsed(&pSink->MixBuf);
    959         cbReadable = PDMAudioPropsFramesToBytes(&pSink->PCMProps, cFrames);
    960     }
    961 
    962     Log3Func(("[%s] cbReadable=%RU32\n", pSink->pszName, cbReadable));
    963 
    964     int rc2 = RTCritSectLeave(&pSink->CritSect);
    965     AssertRC(rc2);
    966 
     793        cbReadable = AudioMixBufUsedBytes(&pSink->MixBuf);
     794
     795    RTCritSectLeave(&pSink->CritSect);
     796    Log3Func(("[%s] cbReadable=%#x\n", pSink->pszName, cbReadable));
    967797    return cbReadable;
    968798}
    969799
    970 /**
    971  * Returns the amount of bytes ready to be written to a sink since the last call
    972  * to AudioMixerSinkUpdate().
    973  *
    974  * @returns Amount of bytes ready to be written to the sink.
    975  * @param   pSink               Sink to return number of available bytes for.
     800
     801/**
     802 * Get the number of bytes that can be written to be sink.
     803 *
     804 * @returns Number of bytes.
     805 * @param   pSink   The mixer sink.
     806 *
     807 * @note    Only applicable to output sinks, will assert and return zero for
     808 *          other sink directions.
    976809 */
    977810uint32_t AudioMixerSinkGetWritable(PAUDMIXSINK pSink)
    978811{
    979812    AssertPtrReturn(pSink, 0);
    980     Assert(pSink->uMagic == AUDMIXSINK_MAGIC);
    981     AssertMsg(pSink->enmDir == PDMAUDIODIR_OUT, ("%s: Can't write to a non-output sink\n", pSink->pszName));
     813    AssertReturn(pSink->uMagic == AUDMIXSINK_MAGIC, 0);
     814    AssertMsgReturn(pSink->enmDir == PDMAUDIODIR_OUT, ("%s: Can't write to a non-output sink\n", pSink->pszName), 0);
    982815
    983816    int rc = RTCritSectEnter(&pSink->CritSect);
     
    985818
    986819    uint32_t cbWritable = 0;
    987 
    988     if (    (pSink->fStatus & AUDMIXSINK_STS_RUNNING)
    989         && !(pSink->fStatus & AUDMIXSINK_STS_DRAINING))
    990     {
     820    if ((pSink->fStatus & (AUDMIXSINK_STS_RUNNING | AUDMIXSINK_STS_DRAINING)) == AUDMIXSINK_STS_RUNNING)
    991821        cbWritable = AudioMixBufFreeBytes(&pSink->MixBuf);
    992     }
    993 
    994     Log3Func(("[%s] cbWritable=%RU32 (%RU64ms)\n",
    995               pSink->pszName, cbWritable, PDMAudioPropsBytesToMilli(&pSink->PCMProps, cbWritable)));
    996 
    997     int rc2 = RTCritSectLeave(&pSink->CritSect);
    998     AssertRC(rc2);
    999 
     822
     823    RTCritSectLeave(&pSink->CritSect);
     824    Log3Func(("[%s] cbWritable=%#x (%RU64ms)\n", pSink->pszName, cbWritable,
     825              PDMAudioPropsBytesToMilli(&pSink->PCMProps, cbWritable) ));
    1000826    return cbWritable;
    1001827}
    1002828
    1003 /**
    1004  * Returns the sink's mixing direction.
     829
     830/**
     831 * Get the sink's mixing direction.
    1005832 *
    1006833 * @returns Mixing direction.
    1007  * @param   pSink               Sink to return direction for.
    1008  */
    1009 PDMAUDIODIR AudioMixerSinkGetDir(PAUDMIXSINK pSink)
     834 * @param   pSink   The mixer sink.
     835 */
     836PDMAUDIODIR AudioMixerSinkGetDir(PCAUDMIXSINK pSink)
    1010837{
    1011838    AssertPtrReturn(pSink, PDMAUDIODIR_INVALID);
    1012     Assert(pSink->uMagic == AUDMIXSINK_MAGIC);
    1013 
    1014     /** @todo the sink direction should be static...    */
     839    AssertReturn(pSink->uMagic == AUDMIXSINK_MAGIC, PDMAUDIODIR_INVALID);
     840
     841    /* The sink direction cannot be changed after creation, so no need for locking here.  */
     842    return pSink->enmDir;
     843}
     844
     845
     846/**
     847 * Get the sink status.
     848 *
     849 * @returns AUDMIXSINK_STS_XXX
     850 * @param   pSink   The mixer sink.
     851 */
     852uint32_t AudioMixerSinkGetStatus(PAUDMIXSINK pSink)
     853{
     854    AssertPtrReturn(pSink, AUDMIXSINK_STS_NONE);
     855    AssertReturn(pSink->uMagic == AUDMIXSINK_MAGIC, AUDMIXSINK_STS_NONE);
     856
    1015857    int rc = RTCritSectEnter(&pSink->CritSect);
    1016     AssertRCReturn(rc, PDMAUDIODIR_INVALID);
    1017 
    1018     PDMAUDIODIR const  enmDir = pSink->enmDir;
    1019 
    1020     int rc2 = RTCritSectLeave(&pSink->CritSect);
    1021     AssertRC(rc2);
    1022 
    1023     return enmDir;
    1024 }
    1025 
    1026 /**
    1027  * Returns the current status of a mixer sink.
    1028  *
    1029  * @returns The sink's current status (AUDMIXSINK_STS_XXX).
    1030  * @param   pSink               Mixer sink to return status for.
    1031  */
    1032 uint32_t AudioMixerSinkGetStatus(PAUDMIXSINK pSink)
    1033 {
    1034     if (!pSink)
    1035         return AUDMIXSINK_STS_NONE;
    1036     AssertPtr(pSink);
    1037     Assert(pSink->uMagic == AUDMIXSINK_MAGIC);
    1038 
    1039     int rc2 = RTCritSectEnter(&pSink->CritSect);
    1040     AssertRCReturn(rc2, AUDMIXSINK_STS_NONE);
    1041 
    1042     /* If the dirty flag is set, there is unprocessed data in the sink. */
     858    AssertRCReturn(rc, AUDMIXSINK_STS_NONE);
     859
    1043860    uint32_t const fStsSink = pSink->fStatus;
    1044861
    1045     rc2 = RTCritSectLeave(&pSink->CritSect);
    1046     AssertRC(rc2);
    1047 
     862    RTCritSectLeave(&pSink->CritSect);
    1048863    return fStsSink;
    1049864}
    1050865
    1051 /**
    1052  * Returns whether the sink is in an active state or not.
    1053  *
    1054  * @note The pending disable state also counts as active.
    1055  *
    1056  * @returns True if active, false if not.
    1057  * @param   pSink               Sink to return active state for.
     866
     867/**
     868 * Checks if the sink is active not.
     869 *
     870 * @note    The pending disable state also counts as active.
     871 *
     872 * @retval  true if active.
     873 * @retval  false if not active.
     874 * @param   pSink   The mixer sink.  NULL is okay (returns false).
    1058875 */
    1059876bool AudioMixerSinkIsActive(PAUDMIXSINK pSink)
     
    1062879        return false;
    1063880    AssertPtr(pSink);
    1064     Assert(pSink->uMagic == AUDMIXSINK_MAGIC);
    1065 
    1066     int rc2 = RTCritSectEnter(&pSink->CritSect);
    1067     AssertRCReturn(rc2, false);
    1068 
    1069     const bool fIsActive = pSink->fStatus & AUDMIXSINK_STS_RUNNING;
    1070     /* Note: AUDMIXSINK_STS_PENDING_DISABLE implies AUDMIXSINK_STS_RUNNING. */
    1071 
    1072     Log3Func(("[%s] fActive=%RTbool\n", pSink->pszName, fIsActive));
    1073 
    1074     rc2 = RTCritSectLeave(&pSink->CritSect);
    1075     AssertRC(rc2);
    1076 
     881    AssertReturn(pSink->uMagic == AUDMIXSINK_MAGIC, false);
     882
     883    int rc = RTCritSectEnter(&pSink->CritSect);
     884    AssertRCReturn(rc, false);
     885
     886    bool const fIsActive = RT_BOOL(pSink->fStatus & AUDMIXSINK_STS_RUNNING);
     887
     888    RTCritSectLeave(&pSink->CritSect);
     889    Log3Func(("[%s] returns %RTbool\n", pSink->pszName, fIsActive));
    1077890    return fIsActive;
    1078891}
    1079892
    1080 /**
    1081  * Removes a mixer stream from a mixer sink, internal version.
    1082  *
    1083  * @returns VBox status code.
    1084  * @param   pSink               Sink to remove mixer stream from.
    1085  * @param   pStream             Stream to remove.
    1086  */
    1087 static int audioMixerSinkRemoveStreamInternal(PAUDMIXSINK pSink, PAUDMIXSTREAM pStream)
    1088 {
    1089     AssertPtrReturn(pSink, VERR_INVALID_PARAMETER);
    1090     if (pStream)
    1091     { /* likely */ }
    1092     else
    1093         return VERR_NOT_FOUND;
    1094     AssertMsgReturn(pStream->pSink == pSink, ("Stream '%s' is not part of sink '%s'\n",
    1095                                               pStream->pszName, pSink->pszName), VERR_NOT_FOUND);
    1096 
    1097     LogFlowFunc(("[%s] (Stream = %s), cStreams=%RU8\n",
    1098                  pSink->pszName, pStream->pStream->szName, pSink->cStreams));
    1099 
    1100     /* Remove stream from sink. */
    1101     RTListNodeRemove(&pStream->Node);
    1102 
    1103     /* Set sink to NULL so that we know we're not part of any sink anymore. */
    1104     pStream->pSink = NULL;
    1105 
    1106     return VINF_SUCCESS;
    1107 }
    1108 
    1109 /**
    1110  * Removes a mixer stream from a mixer sink.
    1111  *
    1112  * @param   pSink               Sink to remove mixer stream from.
    1113  * @param   pStream             Stream to remove.
    1114  */
    1115 void AudioMixerSinkRemoveStream(PAUDMIXSINK pSink, PAUDMIXSTREAM pStream)
    1116 {
    1117     AssertPtr(pSink);
    1118     Assert(pSink->uMagic == AUDMIXSINK_MAGIC);
    1119     if (pStream)
    1120         Assert(pStream->uMagic == AUDMIXSTREAM_MAGIC);
    1121 
    1122     int rc2 = RTCritSectEnter(&pSink->CritSect);
    1123     AssertRC(rc2);
    1124 
    1125     rc2 = audioMixerSinkRemoveStreamInternal(pSink, pStream);
    1126     if (RT_SUCCESS(rc2))
    1127     {
    1128         Assert(pSink->cStreams);
    1129         pSink->cStreams--;
    1130     }
    1131 
    1132     rc2 = RTCritSectLeave(&pSink->CritSect);
    1133     AssertRC(rc2);
    1134 }
    1135 
    1136 /**
    1137  * Removes all attached streams from a given sink.
    1138  *
    1139  * @param pSink                 Sink to remove attached streams from.
    1140  */
    1141 static void audioMixerSinkRemoveAllStreamsInternal(PAUDMIXSINK pSink)
     893
     894/**
     895 * Resets the sink's state.
     896 *
     897 * @param   pSink       The sink to reset.
     898 * @note    Must own sink lock.
     899 */
     900static void audioMixerSinkResetInternal(PAUDMIXSINK pSink)
     901{
     902    Assert(RTCritSectIsOwner(&pSink->CritSect));
     903    LogFunc(("[%s]\n", pSink->pszName));
     904
     905    /* Drop mixing buffer content. */
     906    AudioMixBufDrop(&pSink->MixBuf);
     907
     908    /* Reset status. */
     909    pSink->fStatus         = AUDMIXSINK_STS_NONE;
     910    pSink->tsLastUpdatedMs = 0;
     911}
     912
     913
     914/**
     915 * Resets a sink. This will immediately stop all processing.
     916 *
     917 * @param pSink                 Sink to reset.
     918 */
     919void AudioMixerSinkReset(PAUDMIXSINK pSink)
    1142920{
    1143921    if (!pSink)
    1144922        return;
    1145 
    1146     LogFunc(("%s\n", pSink->pszName));
    1147 
    1148     PAUDMIXSTREAM pStream, pStreamNext;
    1149     RTListForEachSafe(&pSink->lstStreams, pStream, pStreamNext, AUDMIXSTREAM, Node)
    1150         audioMixerSinkRemoveStreamInternal(pSink, pStream);
    1151 }
    1152 
    1153 /**
    1154  * Removes all attached streams from a given sink.
    1155  *
    1156  * @param pSink                 Sink to remove attached streams from.
    1157  */
    1158 void AudioMixerSinkRemoveAllStreams(PAUDMIXSINK pSink)
    1159 {
    1160     if (!pSink)
    1161         return;
    1162 
    1163     int rc2 = RTCritSectEnter(&pSink->CritSect);
    1164     AssertRC(rc2);
    1165 
    1166     audioMixerSinkRemoveAllStreamsInternal(pSink);
    1167 
    1168     pSink->cStreams = 0;
    1169 
    1170     rc2 = RTCritSectLeave(&pSink->CritSect);
    1171     AssertRC(rc2);
    1172 }
    1173 
    1174 /**
    1175  * Resets the sink's state.
    1176  *
    1177  * @param   pSink               Sink to reset.
    1178  */
    1179 static void audioMixerSinkReset(PAUDMIXSINK pSink)
    1180 {
    1181     if (!pSink)
    1182         return;
    1183 
    1184     LogFunc(("[%s]\n", pSink->pszName));
    1185 
    1186     AudioMixBufDrop(&pSink->MixBuf);
    1187 
    1188     /* Update last updated timestamp. */
    1189     pSink->tsLastUpdatedMs = 0;
    1190 
    1191     /* Reset status. */
    1192     pSink->fStatus = AUDMIXSINK_STS_NONE;
    1193 }
    1194 
    1195 /**
    1196  * Resets a sink. This will immediately stop all processing.
    1197  *
    1198  * @param pSink                 Sink to reset.
    1199  */
    1200 void AudioMixerSinkReset(PAUDMIXSINK pSink)
    1201 {
    1202     if (!pSink)
    1203         return;
    1204 
    1205     int rc2 = RTCritSectEnter(&pSink->CritSect);
    1206     AssertRC(rc2);
     923    AssertReturnVoid(pSink->uMagic == AUDMIXSINK_MAGIC);
     924
     925    int rc = RTCritSectEnter(&pSink->CritSect);
     926    AssertRCReturnVoid(rc);
    1207927
    1208928    LogFlowFunc(("[%s]\n", pSink->pszName));
    1209929
    1210     audioMixerSinkReset(pSink);
    1211 
    1212     rc2 = RTCritSectLeave(&pSink->CritSect);
    1213     AssertRC(rc2);
    1214 }
     930    /*
     931     * Stop any stream that's enabled before resetting the state.
     932     */
     933    PAUDMIXSTREAM pStream;
     934    RTListForEach(&pSink->lstStreams, pStream, AUDMIXSTREAM, Node)
     935    {
     936        if (pStream->fStatus & AUDMIXSTREAM_STATUS_ENABLED)
     937            audioMixerStreamCtlInternal(pStream, PDMAUDIOSTREAMCMD_DISABLE);
     938    }
     939
     940    /*
     941     * Reset the state.
     942     */
     943    audioMixerSinkResetInternal(pSink);
     944
     945    RTCritSectLeave(&pSink->CritSect);
     946}
     947
    1215948
    1216949/**
     
    1219952 * @returns VBox status code.
    1220953 * @param   pSink   The sink to set audio format for.
    1221  * @param   pProps  The properties of the new audio format.
     954 * @param   pProps  The properties of the new audio format (guest side).
    1222955 */
    1223956int AudioMixerSinkSetFormat(PAUDMIXSINK pSink, PCPDMAUDIOPCMPROPS pProps)
     
    1232965
    1233966    /*
    1234      * Nothing to do here unless the format changed.
     967     * Do nothing unless the format actually changed.
    1235968     */
    1236969    if (!PDMAudioPropsAreEqual(&pSink->PCMProps, pProps))
     
    1241974        if (PDMAudioPropsHz(&pSink->PCMProps) != 0)
    1242975            LogFlowFunc(("[%s] Old format: %s\n", pSink->pszName, PDMAudioPropsToString(&pSink->PCMProps, szTmp, sizeof(szTmp)) ));
    1243 
    1244976        pSink->PCMProps = *pProps;
    1245977        LogFlowFunc(("[%s] New format: %s\n", pSink->pszName, PDMAudioPropsToString(&pSink->PCMProps, szTmp, sizeof(szTmp)) ));
     
    1248980         * Also update the sink's mixing buffer format.
    1249981         */
    1250         AudioMixBufDestroy(&pSink->MixBuf);
     982        AudioMixBufTerm(&pSink->MixBuf);
    1251983
    1252984        /** @todo r=bird: Make sure we've got more room here than what's expected to
     
    13171049}
    13181050
    1319 /**
    1320  * Sets the volume of an individual sink.
     1051
     1052/**
     1053 * Updates the combined volume (sink + mixer) of a mixer sink.
    13211054 *
    13221055 * @returns VBox status code.
    1323  * @param   pSink               Sink to set volume for.
    1324  * @param   pVol                Volume to set.
    1325  */
    1326 int AudioMixerSinkSetVolume(PAUDMIXSINK pSink, PPDMAUDIOVOLUME pVol)
     1056 * @param   pSink       The mixer sink to update volume for (valid).
     1057 * @param   pVolMaster  The master (mixer) volume (valid).
     1058 */
     1059static int audioMixerSinkUpdateVolume(PAUDMIXSINK pSink, PCPDMAUDIOVOLUME pVolMaster)
     1060{
     1061    AssertPtr(pSink);
     1062    Assert(pSink->uMagic == AUDMIXSINK_MAGIC);
     1063    AssertPtr(pVolMaster);
     1064    LogFlowFunc(("[%s] Master fMuted=%RTbool, lVol=%RU32, rVol=%RU32\n",
     1065                  pSink->pszName, pVolMaster->fMuted, pVolMaster->uLeft, pVolMaster->uRight));
     1066
     1067    pSink->VolumeCombined.fMuted = pVolMaster->fMuted || pSink->Volume.fMuted;
     1068    /** @todo Very crude implementation for now -- needs more work! */
     1069    pSink->VolumeCombined.uLeft  = (uint32_t)RT_MAX(pSink->Volume.uLeft, 1)  * RT_MAX(pVolMaster->uLeft, 1)  / PDMAUDIO_VOLUME_MAX;
     1070    pSink->VolumeCombined.uRight = (uint32_t)RT_MAX(pSink->Volume.uRight, 1) * RT_MAX(pVolMaster->uRight, 1) / PDMAUDIO_VOLUME_MAX;
     1071
     1072    LogFlowFunc(("[%s] fMuted=%RTbool, lVol=%RU32, rVol=%RU32 -> fMuted=%RTbool, lVol=%RU32, rVol=%RU32\n",
     1073                 pSink->pszName, pSink->Volume.fMuted, pSink->Volume.uLeft, pSink->Volume.uRight,
     1074                 pSink->VolumeCombined.fMuted, pSink->VolumeCombined.uLeft, pSink->VolumeCombined.uRight));
     1075
     1076    AudioMixBufSetVolume(&pSink->MixBuf, &pSink->VolumeCombined);
     1077    return VINF_SUCCESS;
     1078}
     1079
     1080
     1081/**
     1082 * Sets the volume a mixer sink.
     1083 *
     1084 * @returns VBox status code.
     1085 * @param   pSink       The sink to set volume for.
     1086 * @param   pVol        New volume settings.
     1087 */
     1088int AudioMixerSinkSetVolume(PAUDMIXSINK pSink, PCPDMAUDIOVOLUME pVol)
    13271089{
    13281090    AssertPtrReturn(pSink, VERR_INVALID_POINTER);
    1329     Assert(pSink->uMagic == AUDMIXSINK_MAGIC);
    1330     AssertPtrReturn(pVol,  VERR_INVALID_POINTER);
     1091    AssertReturn(pSink->uMagic == AUDMIXSINK_MAGIC, VERR_INVALID_MAGIC);
     1092    AssertPtrReturn(pVol, VERR_INVALID_POINTER);
    13311093
    13321094    int rc = RTCritSectEnter(&pSink->CritSect);
     
    13381100             pSink->pszName, pVol->uLeft, pVol->uRight, pVol->fMuted ? "Muted" : "Unmuted"));
    13391101
    1340     AssertPtr(pSink->pParent);
    1341     rc = audioMixerSinkUpdateVolume(pSink, &pSink->pParent->VolMaster);
    1342 
    1343     int rc2 = RTCritSectLeave(&pSink->CritSect);
    1344     AssertRC(rc2);
     1102    Assert(pSink->pParent);
     1103    if (pSink->pParent)
     1104        rc = audioMixerSinkUpdateVolume(pSink, &pSink->pParent->VolMaster);
     1105
     1106    RTCritSectLeave(&pSink->CritSect);
    13451107
    13461108    return rc;
     
    19031665            LogFunc(("Sink '%s': All %u streams disabled. Drain done after %RU64 ns.\n",
    19041666                     pSink->pszName, cStreamsDisabled, nsNow - pSink->nsDrainStarted));
    1905             audioMixerSinkReset(pSink); /* clears the status */
     1667            audioMixerSinkResetInternal(pSink); /* clears the status */
    19061668        }
    19071669    }
     
    19141676            pMixStream->pConn->pfnStreamControl(pMixStream->pConn, pMixStream->pStream, PDMAUDIOSTREAMCMD_DISABLE);
    19151677        }
    1916         audioMixerSinkReset(pSink); /* clears the status */
     1678        audioMixerSinkResetInternal(pSink); /* clears the status */
    19171679    }
    19181680
     
    21631925
    21641926/**
     1927 * Writes data to a mixer output sink.
     1928 *
     1929 * @param   pSink       The sink to write data to.
     1930 * @param   pvBuf       Buffer containing the audio data to write.
     1931 * @param   cbBuf       How many bytes to write.
     1932 * @param   pcbWritten  Number of bytes written.
     1933 *
     1934 * @todo merge with caller.
     1935 */
     1936static void audioMixerSinkWrite(PAUDMIXSINK pSink, const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten)
     1937{
     1938    uint32_t cFrames   = AudioMixBufFree(&pSink->MixBuf);
     1939    uint32_t cbToWrite = PDMAudioPropsFramesToBytes(&pSink->PCMProps, cFrames);
     1940    cbToWrite = RT_MIN(cbToWrite, cbBuf);
     1941    AudioMixBufWrite(&pSink->MixBuf, &pSink->Out.State, pvBuf, cbToWrite, 0 /*offDstFrame*/, cFrames, &cFrames);
     1942    Assert(cbToWrite == PDMAudioPropsFramesToBytes(&pSink->PCMProps, cFrames));
     1943    AudioMixBufCommit(&pSink->MixBuf, cFrames);
     1944    *pcbWritten = cbToWrite;
     1945
     1946    /* Update the sink's last written time stamp. */
     1947    pSink->tsLastReadWrittenNs = RTTimeNanoTS();
     1948
     1949    Log3Func(("[%s] cbBuf=%#x -> cbWritten=%#x\n", pSink->pszName, cbBuf, cbToWrite));
     1950}
     1951
     1952
     1953/**
    21651954 * Transfer data from the device's DMA buffer and into the sink.
    21661955 *
     
    21851974    AssertReturn(pCircBuf, offStream);
    21861975    Assert(RTCritSectIsOwner(&pSink->CritSect));
     1976    Assert(pSink->enmDir == PDMAUDIODIR_OUT);
    21871977    RT_NOREF(idStream);
    21881978
     
    22112001
    22122002        uint32_t cbWritten = 0;
    2213         int rc = AudioMixerSinkWrite(pSink, pvSrcBuf, (uint32_t)cbSrcBuf, &cbWritten);
    2214         AssertRC(rc);
     2003        audioMixerSinkWrite(pSink, pvSrcBuf, (uint32_t)cbSrcBuf, &cbWritten);
    22152004        Assert(cbWritten <= cbSrcBuf);
    22162005
     
    24122201
    24132202/**
    2414  * Updates the (master) volume of a mixer sink.
     2203 * Creates an audio mixer stream.
    24152204 *
    24162205 * @returns VBox status code.
    2417  * @param   pSink               Mixer sink to update volume for.
    2418  * @param   pVolMaster          Master volume to set.
    2419  */
    2420 static int audioMixerSinkUpdateVolume(PAUDMIXSINK pSink, PCPDMAUDIOVOLUME pVolMaster)
    2421 {
    2422     AssertPtrReturn(pSink,      VERR_INVALID_POINTER);
     2206 * @param   pSink       Sink to use for creating the stream.
     2207 * @param   pConn       Audio connector interface to use.
     2208 * @param   pCfg        Audio stream configuration to use.  This may be modified
     2209 *                      in some unspecified way (see
     2210 *                      PDMIAUDIOCONNECTOR::pfnStreamCreate).
     2211 * @param   pDevIns     The device instance to register statistics with.
     2212 * @param   ppStream    Pointer which receives the newly created audio stream.
     2213 */
     2214int AudioMixerSinkCreateStream(PAUDMIXSINK pSink, PPDMIAUDIOCONNECTOR pConn, PPDMAUDIOSTREAMCFG pCfg,
     2215                               PPDMDEVINS pDevIns, PAUDMIXSTREAM *ppStream)
     2216{
     2217    AssertPtrReturn(pSink, VERR_INVALID_POINTER);
    24232218    Assert(pSink->uMagic == AUDMIXSINK_MAGIC);
    2424     AssertPtrReturn(pVolMaster, VERR_INVALID_POINTER);
    2425 
    2426     LogFlowFunc(("[%s] Master fMuted=%RTbool, lVol=%RU32, rVol=%RU32\n",
    2427                   pSink->pszName, pVolMaster->fMuted, pVolMaster->uLeft, pVolMaster->uRight));
    2428     LogFlowFunc(("[%s] fMuted=%RTbool, lVol=%RU32, rVol=%RU32 ",
    2429                   pSink->pszName, pSink->Volume.fMuted, pSink->Volume.uLeft, pSink->Volume.uRight));
    2430 
    2431     /** @todo Very crude implementation for now -- needs more work! */
    2432 
    2433     pSink->VolumeCombined.fMuted  = pVolMaster->fMuted || pSink->Volume.fMuted;
    2434 
    2435     pSink->VolumeCombined.uLeft   = (  (pSink->Volume.uLeft ? pSink->Volume.uLeft : 1)
    2436                                      * (pVolMaster->uLeft   ? pVolMaster->uLeft   : 1)) / PDMAUDIO_VOLUME_MAX;
    2437 
    2438     pSink->VolumeCombined.uRight  = (  (pSink->Volume.uRight ? pSink->Volume.uRight : 1)
    2439                                      * (pVolMaster->uRight   ? pVolMaster->uRight   : 1)) / PDMAUDIO_VOLUME_MAX;
    2440 
    2441     LogFlow(("-> fMuted=%RTbool, lVol=%RU32, rVol=%RU32\n",
    2442              pSink->VolumeCombined.fMuted, pSink->VolumeCombined.uLeft, pSink->VolumeCombined.uRight));
    2443 
    2444     AudioMixBufSetVolume(&pSink->MixBuf, &pSink->VolumeCombined);
    2445     return VINF_SUCCESS;
    2446 }
    2447 
    2448 /**
    2449  * Writes data to a mixer output sink.
     2219    AssertPtrReturn(pConn, VERR_INVALID_POINTER);
     2220    AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
     2221    AssertPtrNullReturn(ppStream, VERR_INVALID_POINTER);
     2222    Assert(pSink->AIO.pDevIns == pDevIns); RT_NOREF(pDevIns); /* we'll probably be adding more statistics */
     2223    AssertReturn(pCfg->enmDir == pSink->enmDir, VERR_MISMATCH);
     2224
     2225    /*
     2226     * Check status and get the host driver config.
     2227     */
     2228    if (pConn->pfnGetStatus(pConn, PDMAUDIODIR_DUPLEX) == PDMAUDIOBACKENDSTS_NOT_ATTACHED)
     2229        return VERR_AUDIO_BACKEND_NOT_ATTACHED;
     2230
     2231    PDMAUDIOBACKENDCFG BackendCfg;
     2232    int rc = pConn->pfnGetConfig(pConn, &BackendCfg);
     2233    AssertRCReturn(rc, rc);
     2234
     2235    /*
     2236     * Allocate the instance.
     2237     */
     2238    PAUDMIXSTREAM pMixStream = (PAUDMIXSTREAM)RTMemAllocZ(sizeof(AUDMIXSTREAM));
     2239    AssertReturn(pMixStream, VERR_NO_MEMORY);
     2240
     2241    /* Assign the backend's name to the mixer stream's name for easier identification in the (release) log. */
     2242    pMixStream->pszName = RTStrAPrintf2("[%s] %s", pCfg->szName, BackendCfg.szName);
     2243    pMixStream->pszStatPrefix = RTStrAPrintf2("MixerSink-%s/%s/", pSink->pszName, BackendCfg.szName);
     2244    if (pMixStream->pszName && pMixStream->pszStatPrefix)
     2245    {
     2246        rc = RTCritSectInit(&pMixStream->CritSect);
     2247        if (RT_SUCCESS(rc))
     2248        {
     2249            /*
     2250             * Lock the sink so we can safely get it's properties and call
     2251             * down into the audio driver to create that end of the stream.
     2252             */
     2253            rc = RTCritSectEnter(&pSink->CritSect);
     2254            AssertRC(rc);
     2255            if (RT_SUCCESS(rc))
     2256            {
     2257                LogFlowFunc(("[%s] (enmDir=%ld, %u bits, %RU8 channels, %RU32Hz)\n", pSink->pszName, pCfg->enmDir,
     2258                             PDMAudioPropsSampleBits(&pCfg->Props), PDMAudioPropsChannels(&pCfg->Props), pCfg->Props.uHz));
     2259
     2260                /*
     2261                 * Initialize the host-side configuration for the stream to be created,
     2262                 * this is the sink format & direction with the src/dir, layout, name
     2263                 * and device specific config copied from the guest side config (pCfg).
     2264                 */
     2265                AssertMsg(AudioHlpPcmPropsAreValid(&pSink->PCMProps),
     2266                          ("%s: Does not (yet) have a format set when it must\n", pSink->pszName));
     2267
     2268                PDMAUDIOSTREAMCFG CfgHost;
     2269                rc = PDMAudioStrmCfgInitWithProps(&CfgHost, &pSink->PCMProps);
     2270                AssertRC(rc); /* cannot fail */
     2271                CfgHost.enmDir    = pSink->enmDir;
     2272                CfgHost.enmPath   = pCfg->enmPath;
     2273                CfgHost.enmLayout = pCfg->enmLayout;
     2274                CfgHost.Device    = pCfg->Device;
     2275                RTStrCopy(CfgHost.szName, sizeof(CfgHost.szName), pCfg->szName);
     2276
     2277                /*
     2278                 * Create the stream.
     2279                 *
     2280                 * Output streams are not using any mixing buffers in DrvAudio.  This will
     2281                 * become the norm after we move the input mixing here and convert DevSB16
     2282                 * to use this mixer code too.
     2283                 */
     2284                PPDMAUDIOSTREAM pStream;
     2285                rc = pConn->pfnStreamCreate(pConn, 0 /*fFlags*/, &CfgHost, pCfg, &pStream);
     2286                if (RT_SUCCESS(rc))
     2287                {
     2288                    pMixStream->cFramesBackendBuffer = CfgHost.Backend.cFramesBufferSize;
     2289
     2290                    /* Set up the mixing buffer conversion state. */
     2291                    if (pSink->enmDir == PDMAUDIODIR_IN)
     2292                        rc = AudioMixBufInitWriteState(&pSink->MixBuf, &pMixStream->WriteState, &pStream->Props);
     2293                    else
     2294                        rc = AudioMixBufInitPeekState(&pSink->MixBuf, &pMixStream->PeekState, &pStream->Props);
     2295                    if (RT_SUCCESS(rc))
     2296                    {
     2297                        /* Save the audio stream pointer to this mixing stream. */
     2298                        pMixStream->pStream = pStream;
     2299
     2300                        /* Increase the stream's reference count to let others know
     2301                         * we're relying on it to be around now. */
     2302                        pConn->pfnStreamRetain(pConn, pStream);
     2303                        pMixStream->pConn  = pConn;
     2304                        pMixStream->uMagic = AUDMIXSTREAM_MAGIC;
     2305
     2306                        RTCritSectLeave(&pSink->CritSect);
     2307
     2308                        if (ppStream)
     2309                            *ppStream = pMixStream;
     2310                        return VINF_SUCCESS;
     2311                    }
     2312
     2313                    rc = pConn->pfnStreamDestroy(pConn, pStream, true /*fImmediate*/);
     2314                }
     2315
     2316                /*
     2317                 * Failed.  Tear down the stream.
     2318                 */
     2319                int rc2 = RTCritSectLeave(&pSink->CritSect);
     2320                AssertRC(rc2);
     2321            }
     2322            RTCritSectDelete(&pMixStream->CritSect);
     2323        }
     2324    }
     2325    else
     2326        rc = VERR_NO_STR_MEMORY;
     2327
     2328    RTStrFree(pMixStream->pszStatPrefix);
     2329    pMixStream->pszStatPrefix = NULL;
     2330    RTStrFree(pMixStream->pszName);
     2331    pMixStream->pszName = NULL;
     2332    RTMemFree(pMixStream);
     2333    return rc;
     2334}
     2335
     2336
     2337/**
     2338 * Adds an audio stream to a specific audio sink.
    24502339 *
    24512340 * @returns VBox status code.
    2452  * @param   pSink               Sink to write data to.
    2453  * @param   pvBuf               Buffer containing the audio data to write.
    2454  * @param   cbBuf               Size (in bytes) of the buffer containing the audio data.
    2455  * @param   pcbWritten          Number of bytes written. Optional.
    2456  */
    2457 int AudioMixerSinkWrite(PAUDMIXSINK pSink, const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten)
    2458 {
    2459     AssertPtrReturn(pSink, VERR_INVALID_POINTER);
    2460     AssertReturn(pSink->uMagic == AUDMIXSINK_MAGIC, VERR_INVALID_MAGIC);
    2461     AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
    2462     AssertReturn(cbBuf, VERR_INVALID_PARAMETER);
    2463     AssertPtrNullReturn(pcbWritten, VERR_INVALID_POINTER);
    2464     AssertMsgReturn(pSink->enmDir == PDMAUDIODIR_OUT, ("%s: Can't write to a sink which is not an output sink\n", pSink->pszName),
    2465                     VERR_ACCESS_DENIED);
     2341 * @param   pSink               Sink to add audio stream to.
     2342 * @param   pStream             Stream to add.
     2343 */
     2344int AudioMixerSinkAddStream(PAUDMIXSINK pSink, PAUDMIXSTREAM pStream)
     2345{
     2346    LogFlowFuncEnter();
     2347    AssertPtrReturn(pSink,   VERR_INVALID_POINTER);
     2348    Assert(pSink->uMagic == AUDMIXSINK_MAGIC);
     2349    AssertPtrReturn(pStream, VERR_INVALID_POINTER);
     2350    Assert(pStream->uMagic == AUDMIXSTREAM_MAGIC);
     2351    AssertPtrReturn(pStream->pConn, VERR_AUDIO_STREAM_NOT_READY);
     2352    AssertReturn(pStream->pSink == NULL, VERR_ALREADY_EXISTS);
    24662353
    24672354    int rc = RTCritSectEnter(&pSink->CritSect);
    24682355    AssertRCReturn(rc, rc);
    24692356
    2470     AssertMsgReturnStmt(pSink->fStatus & AUDMIXSINK_STS_RUNNING,
    2471                         ("%s: Can't write to a sink which is not running (anymore) (status 0x%x)\n", pSink->pszName, pSink->fStatus),
    2472                         RTCritSectLeave(&pSink->CritSect), VERR_INVALID_STATE);
    2473 
    2474     uint32_t cFrames   = AudioMixBufFree(&pSink->MixBuf);
    2475     uint32_t cbToWrite = PDMAudioPropsFramesToBytes(&pSink->PCMProps, cFrames);
    2476     cbToWrite = RT_MIN(cbToWrite, cbBuf);
    2477     AudioMixBufWrite(&pSink->MixBuf, &pSink->Out.State, pvBuf, cbToWrite, 0 /*offDstFrame*/, cFrames, &cFrames);
    2478     Assert(cbToWrite == PDMAudioPropsFramesToBytes(&pSink->PCMProps, cFrames));
    2479     AudioMixBufCommit(&pSink->MixBuf, cFrames);
    2480     if (pcbWritten)
    2481         *pcbWritten = cbToWrite;
    2482 
    2483     /* Update the sink's last written time stamp. */
    2484     pSink->tsLastReadWrittenNs = RTTimeNanoTS();
    2485 
    2486     Log3Func(("[%s] cbBuf=%#x -> cbWritten=%#x\n", pSink->pszName, cbBuf, cbToWrite));
    2487 
     2357    AssertLogRelMsgReturnStmt(pSink->cStreams < UINT8_MAX, ("too many streams!\n"), RTCritSectLeave(&pSink->CritSect),
     2358                              VERR_TOO_MANY_OPEN_FILES);
     2359
     2360    /*
     2361     * If the sink is running and not in pending disable mode, make sure that
     2362     * the added stream also is enabled.   Ignore any failure to enable it.
     2363     */
     2364    if (    (pSink->fStatus & AUDMIXSINK_STS_RUNNING)
     2365        && !(pSink->fStatus & AUDMIXSINK_STS_DRAINING))
     2366    {
     2367        audioMixerStreamCtlInternal(pStream, PDMAUDIOSTREAMCMD_ENABLE);
     2368    }
     2369
     2370    /* Save pointer to sink the stream is attached to. */
     2371    pStream->pSink = pSink;
     2372
     2373    /* Append stream to sink's list. */
     2374    RTListAppend(&pSink->lstStreams, &pStream->Node);
     2375    pSink->cStreams++;
     2376
     2377    LogFlowFunc(("[%s] cStreams=%RU8, rc=%Rrc\n", pSink->pszName, pSink->cStreams, rc));
    24882378    RTCritSectLeave(&pSink->CritSect);
     2379    return rc;
     2380}
     2381
     2382
     2383/**
     2384 * Removes a mixer stream from a mixer sink, internal version.
     2385 *
     2386 * @returns VBox status code.
     2387 * @param   pSink       The mixer sink (valid).
     2388 * @param   pStream     The stream to remove (valid).
     2389 *
     2390 * @note    Caller must own the sink lock.
     2391 */
     2392static int audioMixerSinkRemoveStreamInternal(PAUDMIXSINK pSink, PAUDMIXSTREAM pStream)
     2393{
     2394    AssertPtr(pSink);
     2395    AssertPtr(pStream);
     2396    AssertMsgReturn(pStream->pSink == pSink, ("Stream '%s' is not part of sink '%s'\n",
     2397                                              pStream->pszName, pSink->pszName), VERR_NOT_FOUND);
     2398    Assert(RTCritSectIsOwner(&pSink->CritSect));
     2399    LogFlowFunc(("[%s] (Stream = %s), cStreams=%RU8\n", pSink->pszName, pStream->pStream->szName, pSink->cStreams));
     2400
     2401    /*
     2402     * Remove stream from sink, update the count and set the pSink member to NULL.
     2403     */
     2404    RTListNodeRemove(&pStream->Node);
     2405
     2406    Assert(pSink->cStreams > 0);
     2407    pSink->cStreams--;
     2408
     2409    pStream->pSink = NULL;
     2410
    24892411    return VINF_SUCCESS;
    24902412}
     2413
     2414
     2415/**
     2416 * Removes a mixer stream from a mixer sink.
     2417 *
     2418 * @param   pSink       The mixer sink.
     2419 * @param   pStream     The stream to remove.
     2420 */
     2421void AudioMixerSinkRemoveStream(PAUDMIXSINK pSink, PAUDMIXSTREAM pStream)
     2422{
     2423    AssertPtrReturnVoid(pSink);
     2424    AssertReturnVoid(pSink->uMagic == AUDMIXSINK_MAGIC);
     2425    AssertPtrReturnVoid(pStream);
     2426    AssertReturnVoid(pStream->uMagic == AUDMIXSTREAM_MAGIC);
     2427
     2428    int rc = RTCritSectEnter(&pSink->CritSect);
     2429    AssertRCReturnVoid(rc);
     2430
     2431    audioMixerSinkRemoveStreamInternal(pSink, pStream);
     2432
     2433    RTCritSectLeave(&pSink->CritSect);
     2434}
     2435
     2436
     2437/**
     2438 * Removes all streams from a given sink.
     2439 *
     2440 * @param   pSink       The mixer sink. NULL is ignored.
     2441 */
     2442void AudioMixerSinkRemoveAllStreams(PAUDMIXSINK pSink)
     2443{
     2444    if (!pSink)
     2445        return;
     2446    AssertReturnVoid(pSink->uMagic == AUDMIXSINK_MAGIC);
     2447
     2448    int rc = RTCritSectEnter(&pSink->CritSect);
     2449    AssertRCReturnVoid(rc);
     2450
     2451    LogFunc(("%s\n", pSink->pszName));
     2452
     2453    PAUDMIXSTREAM pStream, pStreamNext;
     2454    RTListForEachSafe(&pSink->lstStreams, pStream, pStreamNext, AUDMIXSTREAM, Node)
     2455    {
     2456        audioMixerSinkRemoveStreamInternal(pSink, pStream);
     2457    }
     2458    AssertStmt(pSink->cStreams == 0, pSink->cStreams = 0);
     2459
     2460    RTCritSectLeave(&pSink->CritSect);
     2461}
     2462
    24912463
    24922464
     
    26022574}
    26032575
     2576
    26042577/**
    26052578 * Destroys & frees a mixer stream, internal version.
     
    26152588static void audioMixerStreamDestroyInternal(PAUDMIXSTREAM pMixStream, PPDMDEVINS pDevIns, bool fImmediate)
    26162589{
    2617     AssertPtrReturnVoid(pMixStream);
    2618 
     2590    AssertPtr(pMixStream);
    26192591    LogFunc(("%s\n", pMixStream->pszName));
    26202592    Assert(pMixStream->uMagic == AUDMIXSTREAM_MAGIC);
    26212593
     2594    /*
     2595     * Invalidate it.
     2596     */
     2597    pMixStream->uMagic = AUDMIXSTREAM_MAGIC_DEAD;
     2598
     2599    /*
     2600     * Destroy the driver stream (if any).
     2601     */
    26222602    if (pMixStream->pConn) /* Stream has a connector interface present? */
    26232603    {
     
    26332613    }
    26342614
     2615    /*
     2616     * Stats.  Doing it by prefix is soo much faster than individually, btw.
     2617     */
    26352618    if (pMixStream->pszStatPrefix)
    26362619    {
     
    26402623    }
    26412624
     2625    /*
     2626     * Delete the critsect and free the memory.
     2627     */
     2628    int rc2 = RTCritSectDelete(&pMixStream->CritSect);
     2629    AssertRC(rc2);
     2630
    26422631    RTStrFree(pMixStream->pszName);
    26432632    pMixStream->pszName = NULL;
    26442633
    2645     int rc2 = RTCritSectDelete(&pMixStream->CritSect);
    2646     AssertRC(rc2);
    2647 
    26482634    RTMemFree(pMixStream);
    2649     pMixStream = NULL;
    2650 }
     2635}
     2636
    26512637
    26522638/**
     
    26632649    if (!pMixStream)
    26642650        return;
    2665 
    2666 /** @todo r=bird: Wrng critsect for audioMixerSinkRemoveStreamInternal   */
    2667     int rc2 = RTCritSectEnter(&pMixStream->CritSect);
    2668     AssertRC(rc2);
    2669 
     2651    AssertReturnVoid(pMixStream->uMagic == AUDMIXSTREAM_MAGIC);
    26702652    LogFunc(("%s\n", pMixStream->pszName));
    26712653
    2672     if (pMixStream->pSink) /* Is the stream part of a sink? */
    2673     {
    2674         /* Save sink pointer, as after audioMixerSinkRemoveStreamInternal() the
    2675          * pointer will be gone from the stream. */
    2676         PAUDMIXSINK pSink = pMixStream->pSink;
    2677 
    2678         rc2 = audioMixerSinkRemoveStreamInternal(pSink, pMixStream);
    2679         if (RT_SUCCESS(rc2))
    2680         {
    2681             Assert(pSink->cStreams);
    2682             pSink->cStreams--;
    2683         }
    2684     }
    2685     else
    2686         rc2 = VINF_SUCCESS;
    2687 
    2688     int rc3 = RTCritSectLeave(&pMixStream->CritSect);
    2689     AssertRC(rc3);
    2690 
    2691     if (RT_SUCCESS(rc2))
    2692     {
    2693         audioMixerStreamDestroyInternal(pMixStream, pDevIns, fImmediate);
    2694         pMixStream = NULL;
    2695     }
    2696 
    2697     LogFlowFunc(("Returning %Rrc\n", rc2));
    2698 }
    2699 
     2654    /*
     2655     * Serializing paranoia.
     2656     */
     2657    int rc = RTCritSectEnter(&pMixStream->CritSect);
     2658    AssertRCReturnVoid(rc);
     2659    RTCritSectLeave(&pMixStream->CritSect);
     2660
     2661    /*
     2662     * Unlink from sink if associated with one.
     2663     */
     2664    PAUDMIXSINK pSink = pMixStream->pSink;
     2665    if (   RT_VALID_PTR(pSink)
     2666        && pSink->uMagic == AUDMIXSINK_MAGIC)
     2667    {
     2668        RTCritSectEnter(&pSink->CritSect);
     2669        audioMixerSinkRemoveStreamInternal(pMixStream->pSink, pMixStream);
     2670        RTCritSectLeave(&pSink->CritSect);
     2671    }
     2672    else if (pSink)
     2673        AssertFailed();
     2674
     2675    /*
     2676     * Do the actual stream destruction.
     2677     */
     2678    audioMixerStreamDestroyInternal(pMixStream, pDevIns, fImmediate);
     2679    LogFlowFunc(("returns\n"));
     2680}
     2681
  • trunk/src/VBox/Devices/Audio/AudioMixer.h

    r89357 r89371  
    3535/** Pointer to an audio mixer sink. */
    3636typedef struct AUDMIXSINK *PAUDMIXSINK;
     37/** Pointer to a const audio mixer sink. */
     38typedef struct AUDMIXSINK const *PCAUDMIXSINK;
    3739
    3840
     
    287289/** @name Audio mixer sink methods
    288290 * @{ */
    289 int     AudioMixerSinkAddStream(PAUDMIXSINK pSink, PAUDMIXSTREAM pStream);
    290 int     AudioMixerSinkCreateStream(PAUDMIXSINK pSink, PPDMIAUDIOCONNECTOR pConnector, PPDMAUDIOSTREAMCFG pCfg,
    291                                    PPDMDEVINS pDevIns, PAUDMIXSTREAM *ppStream);
    292 int     AudioMixerSinkStart(PAUDMIXSINK pSink);
    293 int     AudioMixerSinkDrainAndStop(PAUDMIXSINK pSink, uint32_t cbComming);
    294 void AudioMixerSinkDestroy(PAUDMIXSINK pSink, PPDMDEVINS pDevIns);
    295 uint32_t AudioMixerSinkGetReadable(PAUDMIXSINK pSink);
    296 uint32_t AudioMixerSinkGetWritable(PAUDMIXSINK pSink);
    297 PDMAUDIODIR   AudioMixerSinkGetDir(PAUDMIXSINK pSink);
    298 uint32_t AudioMixerSinkGetStatus(PAUDMIXSINK pSink);
    299 bool AudioMixerSinkIsActive(PAUDMIXSINK pSink);
    300 void AudioMixerSinkRemoveStream(PAUDMIXSINK pSink, PAUDMIXSTREAM pStream);
    301 void AudioMixerSinkRemoveAllStreams(PAUDMIXSINK pSink);
    302 void AudioMixerSinkReset(PAUDMIXSINK pSink);
    303 int AudioMixerSinkSetFormat(PAUDMIXSINK pSink, PCPDMAUDIOPCMPROPS pPCMProps);
    304 int AudioMixerSinkSetVolume(PAUDMIXSINK pSink, PPDMAUDIOVOLUME pVol);
    305 int AudioMixerSinkWrite(PAUDMIXSINK pSink, const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten);
    306 int AudioMixerSinkUpdate(PAUDMIXSINK pSink, uint32_t cbDmaUsed, uint32_t cbDmaPeriod);
     291int         AudioMixerSinkStart(PAUDMIXSINK pSink);
     292int         AudioMixerSinkDrainAndStop(PAUDMIXSINK pSink, uint32_t cbComming);
     293void        AudioMixerSinkDestroy(PAUDMIXSINK pSink, PPDMDEVINS pDevIns);
     294uint32_t    AudioMixerSinkGetReadable(PAUDMIXSINK pSink);
     295uint32_t    AudioMixerSinkGetWritable(PAUDMIXSINK pSink);
     296PDMAUDIODIR AudioMixerSinkGetDir(PCAUDMIXSINK pSink);
     297uint32_t    AudioMixerSinkGetStatus(PAUDMIXSINK pSink);
     298bool        AudioMixerSinkIsActive(PAUDMIXSINK pSink);
     299void        AudioMixerSinkReset(PAUDMIXSINK pSink);
     300int         AudioMixerSinkSetFormat(PAUDMIXSINK pSink, PCPDMAUDIOPCMPROPS pPCMProps);
     301int         AudioMixerSinkSetVolume(PAUDMIXSINK pSink, PCPDMAUDIOVOLUME pVol);
     302int         AudioMixerSinkUpdate(PAUDMIXSINK pSink, uint32_t cbDmaUsed, uint32_t cbDmaPeriod);
    307303
    308304int         AudioMixerSinkAddUpdateJob(PAUDMIXSINK pSink, PFNAUDMIXSINKUPDATE pfnUpdate, void *pvUser, uint32_t cMsTypicalInterval);
     
    316312int         AudioMixerSinkTryLock(PAUDMIXSINK pSink);
    317313int         AudioMixerSinkUnlock(PAUDMIXSINK pSink);
     314
     315int         AudioMixerSinkCreateStream(PAUDMIXSINK pSink, PPDMIAUDIOCONNECTOR pConnector, PPDMAUDIOSTREAMCFG pCfg,
     316                                       PPDMDEVINS pDevIns, PAUDMIXSTREAM *ppStream);
     317int         AudioMixerSinkAddStream(PAUDMIXSINK pSink, PAUDMIXSTREAM pStream);
     318void        AudioMixerSinkRemoveStream(PAUDMIXSINK pSink, PAUDMIXSTREAM pStream);
     319void        AudioMixerSinkRemoveAllStreams(PAUDMIXSINK pSink);
    318320/** @} */
    319321
    320322/** @name Audio mixer stream methods
    321323 * @{ */
    322 void AudioMixerStreamDestroy(PAUDMIXSTREAM pStream, PPDMDEVINS pDevIns, bool fImmediate);
     324void        AudioMixerStreamDestroy(PAUDMIXSTREAM pStream, PPDMDEVINS pDevIns, bool fImmediate);
    323325/** @} */
    324326
  • trunk/src/VBox/Devices/Audio/DevIchAc97.cpp

    r89341 r89371  
    911911{
    912912    PAUDMIXSINK pSink = ichac97R3IndexToSink(pThisCC, pStream->u8SD);
    913     bool fIsEnabled = RT_BOOL(AudioMixerSinkGetStatus(pSink) & AUDMIXSINK_STS_RUNNING);
     913    bool fIsEnabled = pSink && (AudioMixerSinkGetStatus(pSink) & AUDMIXSINK_STS_RUNNING);
    914914
    915915    LogFunc(("[SD%RU8] fIsEnabled=%RTbool\n", pStream->u8SD, fIsEnabled));
  • trunk/src/VBox/Devices/Audio/testcase/tstAudioMixBuffer.cpp

    r89351 r89371  
    318318    RTTESTI_CHECK(AudioMixBufReadPos(&mb) == 0);
    319319
    320     AudioMixBufDestroy(&mb);
     320    AudioMixBufTerm(&mb);
    321321}
    322322
     
    674674                       iSrcFrame, cDstMinExpect, cDstMaxExpect, iDstFrame, (cDstMinExpect + cDstMaxExpect) / 2 - iDstFrame));
    675675
    676     AudioMixBufDestroy(&MixBuf);
     676    AudioMixBufTerm(&MixBuf);
    677677}
    678678
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