Changeset 88298 in vbox for trunk/src/VBox/Devices/Audio
- Timestamp:
- Mar 26, 2021 2:02:35 PM (4 years ago)
- svn:sync-xref-src-repo-rev:
- 143511
- Location:
- trunk/src/VBox/Devices/Audio
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Audio/AudioMixer.cpp
r88269 r88298 105 105 static int audioMixerSinkSetRecSourceInternal(PAUDMIXSINK pSink, PAUDMIXSTREAM pStream); 106 106 static int audioMixerSinkUpdateInternal(PAUDMIXSINK pSink); 107 static int audioMixerSinkMultiplexSync(PAUDMIXSINK pSink, AUDMIXOP enmOp, const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWrittenMin);107 static int audioMixerSinkMultiplexSync(PAUDMIXSINK pSink, const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten); 108 108 static int audioMixerSinkWriteToStream(PAUDMIXSINK pSink, PAUDMIXSTREAM pMixStream); 109 109 static int audioMixerSinkWriteToStreamEx(PAUDMIXSINK pSink, PAUDMIXSTREAM pMixStream, uint32_t cbToWrite, uint32_t *pcbWritten); … … 114 114 115 115 116 /** size of output buffer for dbgAudioMixerSinkStatusToStr. */ 117 #define AUDIOMIXERSINK_STATUS_STR_MAX sizeof("RUNNING PENDING_DISABLE DIRTY 0x12345678") 118 116 119 /** 117 120 * Converts a mixer sink status to a string. 118 121 * 119 * @returns Stringified mixer sink status flags. Must be free'd with RTStrFree(). 120 * "NONE" if no flags set. 121 * @param fStatus Mixer sink status to convert. 122 */ 123 static char *dbgAudioMixerSinkStatusToStr(AUDMIXSINKSTS fStatus) 124 { 125 #define APPEND_FLAG_TO_STR(_aFlag) \ 126 if (fStatus & AUDMIXSINK_STS_##_aFlag) \ 127 { \ 128 if (pszFlags) \ 129 { \ 130 rc2 = RTStrAAppend(&pszFlags, " "); \ 131 if (RT_FAILURE(rc2)) \ 132 break; \ 133 } \ 134 \ 135 rc2 = RTStrAAppend(&pszFlags, #_aFlag); \ 136 if (RT_FAILURE(rc2)) \ 137 break; \ 138 } \ 139 140 char *pszFlags = NULL; 141 int rc2 = VINF_SUCCESS; 142 143 if (fStatus == AUDMIXSINK_STS_NONE) /* This is special, as this is value 0. */ 144 { 145 rc2 = RTStrAAppend(&pszFlags, "NONE"); 146 } 147 else 148 { 149 do 150 { 151 APPEND_FLAG_TO_STR(RUNNING); 152 APPEND_FLAG_TO_STR(PENDING_DISABLE); 153 APPEND_FLAG_TO_STR(DIRTY); 154 155 } while (0); 156 } 157 158 if ( RT_FAILURE(rc2) 159 && pszFlags) 160 { 161 RTStrFree(pszFlags); 162 pszFlags = NULL; 163 } 164 165 #undef APPEND_FLAG_TO_STR 166 167 return pszFlags; 122 * @returns pszDst 123 * @param fStatus The mixer sink status. 124 * @param pszDst The output buffer. Must be at least 125 * AUDIOMIXERSINK_STATUS_STR_MAX in length. 126 */ 127 static const char *dbgAudioMixerSinkStatusToStr(AUDMIXSINKSTS fStatus, char pszDst[AUDIOMIXERSINK_STATUS_STR_MAX]) 128 { 129 if (!fStatus) 130 return strcpy(pszDst, "NONE"); 131 static const struct 132 { 133 const char *pszMnemonic; 134 uint32_t cchMnemonic; 135 uint32_t fStatus; 136 } s_aFlags[] = 137 { 138 { RT_STR_TUPLE("RUNNING"), AUDMIXSINK_STS_RUNNING }, 139 { RT_STR_TUPLE("PENDING_DISABLE"), AUDMIXSINK_STS_PENDING_DISABLE }, 140 { RT_STR_TUPLE("DIRTY"), AUDMIXSINK_STS_DIRTY }, 141 }; 142 char *psz = pszDst; 143 for (size_t i = 0; i < RT_ELEMENTS(s_aFlags); i++) 144 if (fStatus & s_aFlags[i].fStatus) 145 { 146 memcpy(psz, s_aFlags[i].pszMnemonic, s_aFlags[i].cchMnemonic); 147 psz += s_aFlags[i].cchMnemonic; 148 fStatus &= ~s_aFlags[i].fStatus; 149 if (!fStatus) 150 { 151 psz[-1] = '\0'; 152 return pszDst; 153 } 154 } 155 RTStrPrintf(psz, AUDIOMIXERSINK_STATUS_STR_MAX - (psz - pszDst), "%#x", fStatus); 156 return pszDst; 168 157 } 169 158 … … 811 800 } 812 801 813 char *pszStatus = dbgAudioMixerSinkStatusToStr(pSink->fStatus); 814 LogRel2(("Audio Mixer: Set new status of sink '%s' to %s\n", pSink->pszName, pszStatus)); 815 LogFlowFunc(("[%s] enmCmd=%RU32, fStatus=%s, rc=%Rrc\n", pSink->pszName, enmSinkCmd, pszStatus, rc)); 816 RTStrFree(pszStatus); 802 #if defined(RTLOG_REL_ENABLED) || defined(LOG_ENABLED) 803 char szStatus[AUDIOMIXERSINK_STATUS_STR_MAX]; 804 #endif 805 LogRel2(("Audio Mixer: Set new status of sink '%s': %s (enmCmd=%RU32 rc=%Rrc)\n", 806 pSink->pszName, dbgAudioMixerSinkStatusToStr(pSink->fStatus, szStatus), enmSinkCmd, rc)); 817 807 818 808 int rc2 = RTCritSectLeave(&pSink->CritSect); … … 1284 1274 1285 1275 #ifdef LOG_ENABLED 1286 char *pszStatus = dbgAudioMixerSinkStatusToStr(pSink->fStatus); 1287 Log2Func(("[%s] cbRead=%RU32, fClean=%RTbool, fStatus=%s, rc=%Rrc\n", pSink->pszName, cbRead, fClean, pszStatus, rc)); 1288 RTStrFree(pszStatus); 1276 char szStatus[AUDIOMIXERSINK_STATUS_STR_MAX]; 1289 1277 #endif 1278 Log2Func(("[%s] cbRead=%RU32, fClean=%RTbool, fStatus=%s, rc=%Rrc\n", 1279 pSink->pszName, cbRead, fClean, dbgAudioMixerSinkStatusToStr(pSink->fStatus, szStatus), rc)); 1290 1280 1291 1281 if (pcbRead) … … 1675 1665 AssertPtrReturn(pSink, VERR_INVALID_POINTER); 1676 1666 1677 int rc = VINF_SUCCESS;1678 1679 1667 #ifdef LOG_ENABLED 1680 char *pszStatus = dbgAudioMixerSinkStatusToStr(pSink->fStatus); 1681 Log3Func(("[%s] fStatus=%s\n", pSink->pszName, pszStatus)); 1682 RTStrFree(pszStatus); 1668 char szStatus[AUDIOMIXERSINK_STATUS_STR_MAX]; 1683 1669 #endif 1670 Log3Func(("[%s] fStatus=%s\n", pSink->pszName, dbgAudioMixerSinkStatusToStr(pSink->fStatus, szStatus))); 1684 1671 1685 1672 /* Sink disabled? Take a shortcut. */ 1686 1673 if (!(pSink->fStatus & AUDMIXSINK_STS_RUNNING)) 1687 return rc;1674 return VINF_SUCCESS; 1688 1675 1689 1676 /* Input sink and no recording source set? Bail out early. */ 1690 1677 if ( pSink->enmDir == AUDMIXSINKDIR_INPUT 1691 1678 && pSink->In.pStreamRecSource == NULL) 1692 return rc;1679 return VINF_SUCCESS; 1693 1680 1694 1681 /* Sanity. */ … … 1710 1697 uint32_t cbToWriteToStreams = AudioMixBufUsedBytes(&pSink->MixBuf); 1711 1698 1699 int rc = VINF_SUCCESS; 1712 1700 while (cbToWriteToStreams) 1713 1701 { 1714 1702 uint32_t cfChunk; 1715 rc = AudioMixBufAcquireReadBlock(&pSink->MixBuf, pSink->pabScratchBuf, RT_MIN(cbToWriteToStreams, (uint32_t)pSink->cbScratchBuf),1716 &cfChunk);1703 rc = AudioMixBufAcquireReadBlock(&pSink->MixBuf, pSink->pabScratchBuf, 1704 RT_MIN(cbToWriteToStreams, (uint32_t)pSink->cbScratchBuf), &cfChunk); 1717 1705 if (RT_FAILURE(rc)) 1718 1706 break; … … 1723 1711 /* Multiplex the current chunk in a synchronized fashion to all connected streams. */ 1724 1712 uint32_t cbChunkWrittenMin = 0; 1725 rc = audioMixerSinkMultiplexSync(pSink, AUDMIXOP_COPY,pSink->pabScratchBuf, cbChunk, &cbChunkWrittenMin);1713 rc = audioMixerSinkMultiplexSync(pSink, pSink->pabScratchBuf, cbChunk, &cbChunkWrittenMin); 1726 1714 if (RT_SUCCESS(rc)) 1727 1715 { … … 1931 1919 1932 1920 const uint32_t cbWritableStream = pMixStream->pConn->pfnStreamGetWritable(pMixStream->pConn, pMixStream->pStream); 1933 cbToWrite = RT_MIN(cbToWrite, RT_MIN((uint32_t)RTCircBufUsed(pCircBuf), cbWritableStream)); 1934 1935 Log3Func(("[%s] cbWritableStream=%RU32, cbToWrite=%RU32\n", 1936 pMixStream->pszName, cbWritableStream, cbToWrite)); 1921 cbToWrite = RT_MIN(cbToWrite, RT_MIN((uint32_t)RTCircBufUsed(pCircBuf), cbWritableStream)); 1922 1923 Log3Func(("[%s] cbWritableStream=%RU32, cbToWrite=%RU32\n", pMixStream->pszName, cbWritableStream, cbToWrite)); 1937 1924 1938 1925 uint32_t cbWritten = 0; … … 1960 1947 break; 1961 1948 } 1962 elseif (rc == VERR_AUDIO_STREAM_NOT_READY)1949 if (rc == VERR_AUDIO_STREAM_NOT_READY) 1963 1950 { 1964 1951 /* Stream is not enabled, just skip. */ … … 2003 1990 * 2004 1991 * @returns IPRT status code. 2005 * @param pSink 2006 * @param enmOp What mixing operation to use. Currently not implemented.2007 * @param pvBuf Pointer toaudio data to write.2008 * @param cbBuf Size (in bytes) of audio data to write.2009 * @param pcbWrittenMin Returns minimum size (in bytes) successfully written to all mixer streams. Optional.2010 */ 2011 static int audioMixerSinkMultiplexSync(PAUDMIXSINK pSink, AUDMIXOP enmOp, const void *pvBuf, uint32_t cbBuf,2012 uint32_t *pcbWrittenMin) 2013 { 1992 * @param pSink Sink to write audio output to. 1993 * @param pvBuf Pointer to audio data to write. 1994 * @param cbBuf Size (in bytes) of audio data to write. 1995 * @param pcbWritten Returns the number of bytes written to each of the 1996 * streams. 1997 */ 1998 static int audioMixerSinkMultiplexSync(PAUDMIXSINK pSink, const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten) 1999 { 2000 Log3Func(("[%s] cbBuf=%RU32\n", pSink->pszName, cbBuf)); 2014 2001 AssertReturn(cbBuf, VERR_INVALID_PARAMETER); 2015 RT_NOREF(enmOp);2016 2017 2002 AssertMsg(pSink->enmDir == AUDMIXSINKDIR_OUTPUT, 2018 2003 ("%s: Can't multiplex to a sink which is not an output sink\n", pSink->pszName)); 2019 2004 2020 int rc = VINF_SUCCESS; 2021 2022 uint32_t cbToWriteMin = UINT32_MAX; 2023 2024 Log3Func(("[%s] cbBuf=%RU32\n", pSink->pszName, cbBuf)); 2025 2005 /* 2006 * Check all enabled streems for buffer space. 2007 */ 2008 uint32_t cbToWrite = UINT32_MAX; 2026 2009 PAUDMIXSTREAM pMixStream; 2027 2010 RTListForEach(&pSink->lstStreams, pMixStream, AUDMIXSTREAM, Node) 2028 2011 { 2029 if (!(pMixStream->fStatus & AUDMIXSTREAM_STATUS_ENABLED)) /* Mixing stream not enabled? Skip handling. */ 2030 { 2012 if (pMixStream->fStatus & AUDMIXSTREAM_STATUS_ENABLED) 2013 { 2014 uint32_t const cbCircFree = (uint32_t)RTCircBufFree(pMixStream->pCircBuf); 2015 cbToWrite = RT_MIN(cbToWrite, cbCircFree); 2016 } 2017 else 2031 2018 Log3Func(("[%s] Stream '%s' disabled, skipping ...\n", pSink->pszName, pMixStream->pszName)); 2032 continue; 2033 } 2034 2035 cbToWriteMin = RT_MIN(cbBuf, RT_MIN(cbToWriteMin, (uint32_t)RTCircBufFree(pMixStream->pCircBuf))); 2036 } 2037 2038 if (cbToWriteMin == UINT32_MAX) /* No space at all? */ 2039 cbToWriteMin = 0; 2040 2041 if (cbToWriteMin) 2042 { 2019 } 2020 if (cbToWrite != UINT32_MAX) 2021 cbToWrite = RT_MIN(cbBuf, cbToWrite); 2022 else 2023 cbToWrite = 0; /* No active streams at all. */ 2024 if (cbToWrite) 2025 { 2026 /* 2027 * Do the copying. 2028 */ 2043 2029 RTListForEach(&pSink->lstStreams, pMixStream, AUDMIXSTREAM, Node) 2044 2030 { 2045 if (!(pMixStream->fStatus & AUDMIXSTREAM_STATUS_ENABLED)) /* Mixing stream not enabled? Skip handling. */ 2046 continue; 2047 2048 PRTCIRCBUF pCircBuf = pMixStream->pCircBuf; 2049 void *pvChunk; 2050 size_t cbChunk; 2051 2052 uint32_t cbWrittenBuf = 0; 2053 uint32_t cbToWriteBuf = cbToWriteMin; 2054 2055 while (cbToWriteBuf) 2031 if (pMixStream->fStatus & AUDMIXSTREAM_STATUS_ENABLED) 2056 2032 { 2057 RTCircBufAcquireWriteBlock(pCircBuf, cbToWriteBuf, &pvChunk, &cbChunk); 2058 2059 if (cbChunk) 2060 memcpy(pvChunk, (uint8_t *)pvBuf + cbWrittenBuf, cbChunk); 2061 2062 RTCircBufReleaseWriteBlock(pCircBuf, cbChunk); 2063 2064 cbWrittenBuf += (uint32_t)cbChunk; 2065 Assert(cbWrittenBuf <= cbBuf); 2066 2067 Assert(cbToWriteBuf >= cbChunk); 2068 cbToWriteBuf -= (uint32_t)cbChunk; 2033 PRTCIRCBUF pCircBuf = pMixStream->pCircBuf; 2034 size_t offWritten = 0; 2035 while (offWritten < cbToWrite) 2036 { 2037 void *pvChunk = NULL; 2038 size_t cbChunk = 0; 2039 RTCircBufAcquireWriteBlock(pCircBuf, cbToWrite - offWritten, &pvChunk, &cbChunk); 2040 2041 memcpy(pvChunk, (uint8_t const *)pvBuf + offWritten, cbChunk); 2042 2043 RTCircBufReleaseWriteBlock(pCircBuf, cbChunk); 2044 2045 offWritten += cbChunk; 2046 } 2047 Assert(offWritten == cbToWrite); 2048 2049 pMixStream->tsLastReadWrittenNs = RTTimeNanoTS(); 2050 Log3Func(("[%s] Mixer stream '%s' -> cbWrittenBuf=%RU32\n", pSink->pszName, pMixStream->pszName, cbToWrite)); 2069 2051 } 2070 2071 if (cbWrittenBuf) /* Update the mixer stream's last written time stamp. */ 2072 pMixStream->tsLastReadWrittenNs = RTTimeNanoTS(); 2073 2074 Log3Func(("[%s] Mixer stream '%s' -> cbWrittenBuf=%RU32\n", pSink->pszName, pMixStream->pszName, cbWrittenBuf)); 2075 } 2076 } 2077 2078 Log3Func(("[%s] cbBuf=%RU32, cbToWriteMin=%RU32\n", pSink->pszName, cbBuf, cbToWriteMin)); 2079 2080 if (pcbWrittenMin) 2081 *pcbWrittenMin = cbToWriteMin; 2082 2083 return rc; 2052 } 2053 } 2054 2055 Log3Func(("[%s] cbBuf=%RU32, cbToWrite=%RU32\n", pSink->pszName, cbBuf, cbToWrite)); 2056 2057 *pcbWritten = cbToWrite; 2058 return VINF_SUCCESS; 2084 2059 } 2085 2060 -
trunk/src/VBox/Devices/Audio/DrvAudio.cpp
r88292 r88298 471 471 * Controls an audio stream. 472 472 * 473 * @returns IPRTstatus code.473 * @returns VBox status code. 474 474 * @param pThis Pointer to driver instance. 475 475 * @param pStream Stream to control. … … 579 579 * If the stream has no backend available, VERR_NOT_FOUND is returned. 580 580 * 581 * @returns IPRTstatus code.581 * @returns VBox status code. 582 582 * @param pThis Pointer to driver instance. 583 583 * @param pStream Stream to control. … … 710 710 * The actual re-initialization will happen at some later point in time. 711 711 * 712 * @returns IPRTstatus code.712 * @returns VBox status code. 713 713 * @param pThis Pointer to driver instance. 714 714 */ … … 738 738 739 739 /** 740 * Re-initializes an audio stream with its existing host and guest stream configuration. 741 * This might be the case if the backend told us we need to re-initialize because something 742 * on the host side has changed. 743 * 744 * Note: Does not touch the stream's status flags. 745 * 746 * @returns IPRT status code. 740 * Re-initializes an audio stream with its existing host and guest stream 741 * configuration. 742 * 743 * This might be the case if the backend told us we need to re-initialize 744 * because something on the host side has changed. 745 * 746 * @note Does not touch the stream's status flags. 747 * 748 * @returns VBox status code. 747 749 * @param pThis Pointer to driver instance. 748 750 * @param pStream Stream to re-initialize. … … 1140 1142 * does the actual mixing between the guest <-> host mixing buffers. 1141 1143 * 1142 * @returns IPRTstatus code.1144 * @returns VBox status code. 1143 1145 * @param pThis Pointer to driver instance. 1144 1146 * @param pStream Stream to iterate. … … 1516 1518 * Captures non-interleaved input from a host stream. 1517 1519 * 1518 * @returns IPRTstatus code.1520 * @returns VBox status code. 1519 1521 * @param pThis Driver instance. 1520 1522 * @param pStream Stream to capture from. … … 1620 1622 * Needed for e.g. the VRDP audio backend (in Main). 1621 1623 * 1622 * @returns IPRTstatus code.1624 * @returns VBox status code. 1623 1625 * @param pThis Driver instance. 1624 1626 * @param pStream Stream to capture from. … … 1935 1937 * @note Must not hold the driver's critical section! 1936 1938 * 1937 * @returns IPRTstatus code.1939 * @returns VBox status code. 1938 1940 * @param pThis Driver instance to be called. 1939 1941 * @param fLog Whether to print the enumerated device to the release log or not. … … 2012 2014 { 2013 2015 LogFlowFuncEnter(); 2014 AssertPtrReturn(pThis, VERR_INVALID_POINTER); 2015 2016 2017 /* 2018 * Check the function pointers, make sure the ones we define as 2019 * mandatory are present. 2020 */ 2021 PPDMIHOSTAUDIO pHostDrvAudio = pThis->pHostDrvAudio; 2022 AssertPtrReturn(pHostDrvAudio, VERR_INVALID_POINTER); 2023 AssertPtrReturn(pHostDrvAudio->pfnInit, VERR_INVALID_POINTER); 2024 AssertPtrNullReturn(pHostDrvAudio->pfnShutdown, VERR_INVALID_POINTER); 2025 AssertPtrReturn(pHostDrvAudio->pfnGetConfig, VERR_INVALID_POINTER); 2026 AssertPtrNullReturn(pHostDrvAudio->pfnGetDevices, VERR_INVALID_POINTER); 2027 AssertPtrNullReturn(pHostDrvAudio->pfnGetStatus, VERR_INVALID_POINTER); 2028 AssertPtrNullReturn(pHostDrvAudio->pfnSetCallback, VERR_INVALID_POINTER); 2029 AssertPtrReturn(pHostDrvAudio->pfnStreamCreate, VERR_INVALID_POINTER); 2030 AssertPtrReturn(pHostDrvAudio->pfnStreamDestroy, VERR_INVALID_POINTER); 2031 AssertPtrReturn(pHostDrvAudio->pfnStreamControl, VERR_INVALID_POINTER); 2032 AssertPtrReturn(pHostDrvAudio->pfnStreamGetReadable, VERR_INVALID_POINTER); 2033 AssertPtrReturn(pHostDrvAudio->pfnStreamGetWritable, VERR_INVALID_POINTER); 2034 AssertPtrNullReturn(pHostDrvAudio->pfnStreamGetPending, VERR_INVALID_POINTER); 2035 AssertPtrReturn(pHostDrvAudio->pfnStreamGetStatus, VERR_INVALID_POINTER); 2036 AssertPtrReturn(pHostDrvAudio->pfnStreamIterate, VERR_INVALID_POINTER); 2037 AssertPtrNullReturn(pHostDrvAudio->pfnStreamPlayBegin, VERR_INVALID_POINTER); 2038 AssertPtrReturn(pHostDrvAudio->pfnStreamPlay, VERR_INVALID_POINTER); 2039 AssertPtrNullReturn(pHostDrvAudio->pfnStreamPlayEnd, VERR_INVALID_POINTER); 2040 AssertPtrNullReturn(pHostDrvAudio->pfnStreamCaptureBegin, VERR_INVALID_POINTER); 2041 AssertPtrReturn(pHostDrvAudio->pfnStreamCapture, VERR_INVALID_POINTER); 2042 AssertPtrNullReturn(pHostDrvAudio->pfnStreamCaptureEnd, VERR_INVALID_POINTER); 2043 2044 /* 2045 * Call the init method. 2046 */ 2047 /** @todo r=bird: This is superfluous. This duplicates the driver 2048 * constructor code. Just get rid of it!! */ 2016 2049 AssertPtr(pThis->pHostDrvAudio); 2017 2050 int rc = pThis->pHostDrvAudio->pfnInit(pThis->pHostDrvAudio); … … 2037 2070 LogFlowFunc(("cStreamsFreeIn=%RU8, cStreamsFreeOut=%RU8\n", pThis->In.cStreamsFree, pThis->Out.cStreamsFree)); 2038 2071 2039 LogRel2(("Audio: Host driver '%s' supports %RU32 input streams and %RU32 output streams at once\n", 2040 pThis->szName, 2041 /* Clamp for logging. Unlimited streams are defined by UINT32_MAX. */ 2042 RT_MIN(64, pThis->In.cStreamsFree), RT_MIN(64, pThis->Out.cStreamsFree))); 2072 LogRel2(("Audio: Host driver '%s' supports %RU32 input streams and %RU32 output streams at once.\n", 2073 pThis->szName, pThis->In.cStreamsFree, pThis->Out.cStreamsFree)); 2043 2074 2044 2075 #ifdef VBOX_WITH_AUDIO_ENUM … … 2089 2120 PPDMAUDIOSTREAM pStream; 2090 2121 RTListForEach(&pThis->lstStreams, pStream, PDMAUDIOSTREAM, ListEntry) 2122 { 2091 2123 drvAudioStreamControlInternal(pThis, pStream, enmCmd); 2124 } 2092 2125 } 2093 2126 … … 2453 2486 * Worker for drvAudioStreamCreate that initializes the audio stream. 2454 2487 * 2455 * @returns IPRTstatus code.2488 * @returns VBox status code. 2456 2489 * @param pThis Pointer to driver instance. 2457 2490 * @param pStream Stream to initialize. … … 3090 3123 3091 3124 /** 3092 * @interface_method_impl{PDMIAUDIOCONNECTOR,pfnStreamDestroy}3093 */3094 static DECLCALLBACK(int) drvAudioStreamDestroy(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream)3095 {3096 PDRVAUDIO pThis = RT_FROM_MEMBER(pInterface, DRVAUDIO, IAudioConnector);3097 AssertPtr(pThis);3098 3099 if (!pStream)3100 return VINF_SUCCESS;3101 AssertPtrReturn(pStream, VERR_INVALID_POINTER);3102 Assert(pStream->uMagic == PDMAUDIOSTREAM_MAGIC);3103 3104 int rc = RTCritSectEnter(&pThis->CritSect);3105 AssertRCReturn(rc, rc);3106 3107 LogRel2(("Audio: Destroying stream '%s'\n", pStream->szName));3108 3109 LogFlowFunc(("[%s] cRefs=%RU32\n", pStream->szName, pStream->cRefs));3110 if (pStream->cRefs <= 1)3111 {3112 rc = drvAudioStreamUninitInternal(pThis, pStream);3113 if (RT_SUCCESS(rc))3114 {3115 if (pStream->enmDir == PDMAUDIODIR_IN)3116 pThis->In.cStreamsFree++;3117 else /* Out */3118 pThis->Out.cStreamsFree++;3119 3120 RTListNodeRemove(&pStream->ListEntry);3121 3122 drvAudioStreamFree(pStream);3123 pStream = NULL;3124 }3125 else3126 LogRel(("Audio: Uninitializing stream '%s' failed with %Rrc\n", pStream->szName, rc));3127 }3128 else3129 rc = VERR_WRONG_ORDER;3130 3131 RTCritSectLeave(&pThis->CritSect);3132 LogFlowFuncLeaveRC(rc);3133 return rc;3134 }3135 3136 /**3137 3125 * Calls the backend to give it the chance to destroy its part of the audio stream. 3138 3126 * 3139 * @returns IPRT status code. 3127 * Called from drvAudioPowerOff, drvAudioStreamUninitInternal and 3128 * drvAudioStreamReInitInternal. 3129 * 3130 * @returns VBox status code. 3140 3131 * @param pThis Pointer to driver instance. 3141 3132 * @param pStream Audio stream destruct backend for. … … 3170 3161 3171 3162 /** 3172 * Uninitializes an audio stream. 3173 * 3174 * @returns IPRT status code. 3163 * Uninitializes an audio stream - worker for drvAudioStreamDestroy, 3164 * drvAudioDestruct and drvAudioStreamCreate. 3165 * 3166 * @returns VBox status code. 3175 3167 * @param pThis Pointer to driver instance. 3176 3168 * @param pStream Pointer to audio stream to uninitialize. 3169 * 3170 * @note Caller owns the critical section. 3177 3171 */ 3178 3172 static int drvAudioStreamUninitInternal(PDRVAUDIO pThis, PPDMAUDIOSTREAM pStream) … … 3226 3220 } 3227 3221 } 3228 else if (pStream->enmDir == PDMAUDIODIR_OUT) 3229 { 3222 else 3223 { 3224 Assert(pStream->enmDir == PDMAUDIODIR_OUT); 3230 3225 #ifdef VBOX_WITH_STATISTICS 3231 3226 PDMDrvHlpSTAMDeregister(pThis->pDrvIns, &pStream->Out.Stats.TotalFramesPlayed); … … 3243 3238 } 3244 3239 } 3240 3241 LogFlowFunc(("Returning %Rrc\n", rc)); 3242 return rc; 3243 } 3244 3245 /** 3246 * @interface_method_impl{PDMIAUDIOCONNECTOR,pfnStreamDestroy} 3247 */ 3248 static DECLCALLBACK(int) drvAudioStreamDestroy(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream) 3249 { 3250 PDRVAUDIO pThis = RT_FROM_MEMBER(pInterface, DRVAUDIO, IAudioConnector); 3251 AssertPtr(pThis); 3252 3253 if (!pStream) 3254 return VINF_SUCCESS; 3255 AssertPtrReturn(pStream, VERR_INVALID_POINTER); 3256 Assert(pStream->uMagic == PDMAUDIOSTREAM_MAGIC); 3257 3258 int rc = RTCritSectEnter(&pThis->CritSect); 3259 AssertRCReturn(rc, rc); 3260 3261 LogRel2(("Audio: Destroying stream '%s'\n", pStream->szName)); 3262 3263 LogFlowFunc(("[%s] cRefs=%RU32\n", pStream->szName, pStream->cRefs)); 3264 AssertMsg(pStream->cRefs <= 1, ("%u %s\n", pStream->cRefs, pStream->szName)); 3265 if (pStream->cRefs <= 1) 3266 { 3267 rc = drvAudioStreamUninitInternal(pThis, pStream); 3268 if (RT_SUCCESS(rc)) 3269 { 3270 if (pStream->enmDir == PDMAUDIODIR_IN) 3271 pThis->In.cStreamsFree++; 3272 else /* Out */ 3273 pThis->Out.cStreamsFree++; 3274 3275 RTListNodeRemove(&pStream->ListEntry); 3276 3277 drvAudioStreamFree(pStream); 3278 pStream = NULL; 3279 } 3280 else 3281 LogRel(("Audio: Uninitializing stream '%s' failed with %Rrc\n", pStream->szName, rc)); 3282 } 3245 3283 else 3246 AssertFailed(); 3247 3248 LogFlowFunc(("Returning %Rrc\n", rc)); 3284 rc = VERR_WRONG_ORDER; 3285 3286 RTCritSectLeave(&pThis->CritSect); 3287 LogFlowFuncLeaveRC(rc); 3249 3288 return rc; 3250 3289 } … … 3287 3326 LogFlowFuncEnter(); 3288 3327 3289 if (!pThis->pHostDrvAudio) /* If not lower driver is configured, bail out. */ 3290 return; 3291 3292 /* Just destroy the host stream on the backend side. 3293 * The rest will either be destructed by the device emulation or 3294 * in drvAudioDestruct(). */ 3295 PPDMAUDIOSTREAM pStream; 3296 RTListForEach(&pThis->lstStreams, pStream, PDMAUDIOSTREAM, ListEntry) 3297 { 3298 drvAudioStreamControlInternalBackend(pThis, pStream, PDMAUDIOSTREAMCMD_DISABLE); 3299 drvAudioStreamDestroyInternalBackend(pThis, pStream); 3300 } 3301 3302 /* 3303 * Last call for the driver below us. 3304 * Let it know that we reached end of life. 3305 */ 3306 if (pThis->pHostDrvAudio->pfnShutdown) 3307 pThis->pHostDrvAudio->pfnShutdown(pThis->pHostDrvAudio); 3308 3309 pThis->pHostDrvAudio = NULL; 3328 /** @todo locking? */ 3329 if (pThis->pHostDrvAudio) /* If not lower driver is configured, bail out. */ 3330 { 3331 /* 3332 * Just destroy the host stream on the backend side. 3333 * The rest will either be destructed by the device emulation or 3334 * in drvAudioDestruct(). 3335 */ 3336 PPDMAUDIOSTREAM pStream; 3337 RTListForEach(&pThis->lstStreams, pStream, PDMAUDIOSTREAM, ListEntry) 3338 { 3339 drvAudioStreamControlInternalBackend(pThis, pStream, PDMAUDIOSTREAMCMD_DISABLE); 3340 drvAudioStreamDestroyInternalBackend(pThis, pStream); 3341 } 3342 3343 /* 3344 * Last call for the driver below us. 3345 * Let it know that we reached end of life. 3346 */ 3347 if (pThis->pHostDrvAudio->pfnShutdown) 3348 pThis->pHostDrvAudio->pfnShutdown(pThis->pHostDrvAudio); 3349 3350 pThis->pHostDrvAudio = NULL; 3351 } 3310 3352 3311 3353 LogFlowFuncLeave(); … … 3362 3404 */ 3363 3405 rc = drvAudioHostInit(pThis); 3406 if (RT_FAILURE(rc)) 3407 pThis->pHostDrvAudio = NULL; 3364 3408 } 3365 3409 else … … 3367 3411 LogRel(("Audio: Failed to query interface for underlying host driver '%s'\n", pThis->szName)); 3368 3412 rc = PDMDRV_SET_ERROR(pThis->pDrvIns, VERR_PDM_MISSING_INTERFACE_BELOW, 3369 N_(" Host audio backend missing or invalid"));3413 N_("The host audio driver does not implement PDMIHOSTAUDIO!")); 3370 3414 } 3371 3415 }
Note:
See TracChangeset
for help on using the changeset viewer.