VirtualBox

Changeset 89302 in vbox


Ignore:
Timestamp:
May 26, 2021 9:00:51 PM (4 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
144649
Message:

Audio: Reworking the capture (recording) code path, part 1: Start doing device side mixing in preparation of DrvAudio stopping it's mixing. Code for blending/merging more than one input isn't entirely done. Resampling is completely untested. bugref:9890

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

Legend:

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

    r88889 r89302  
    498498            pDst[1] = audioMixBufClipTo##a_Name(pi64Src[1]); \
    499499            AUDMIXBUF_MACRO_LOG(("%p: %RI64 / %RI64 => %RI64 / %RI64\n", \
    500                                  pi64Src[0], pi64Src[0], pi64Src[1], (int64_t)pDst[0], (int64_t)pDst[1])); \
     500                                 &pi64Src[0], pi64Src[0], pi64Src[1], (int64_t)pDst[0], (int64_t)pDst[1])); \
    501501            pDst    += 2; \
    502502            pi64Src += 2; \
     
    543543             pi64Src += 2; /** @todo when we do multi channel mixbuf support, this can change to 1 */ \
    544544        } \
    545     }
    546 
     545    } \
     546    \
     547    /* Decoders for write: */ \
     548    \
     549    /* 2ch -> 2ch */ \
     550    static DECLCALLBACK(void) RT_CONCAT(audioMixBufDecode2ChTo2Ch,a_Name)(int64_t *pi64Dst, void const *pvSrc, uint32_t cFrames, \
     551                                                                          PAUDIOMIXBUFWRITESTATE pState) \
     552    { \
     553        RT_NOREF_PV(pState); \
     554        a_Type const *pSrc = (a_Type const *)pvSrc; \
     555        while (cFrames-- > 0) \
     556        { \
     557            pi64Dst[0] = audioMixBufClipFrom##a_Name(pSrc[0]); \
     558            pi64Dst[1] = audioMixBufClipFrom##a_Name(pSrc[1]); \
     559            AUDMIXBUF_MACRO_LOG(("%p: %RI64 / %RI64 => %RI64 / %RI64\n", \
     560                                 &pSrc[0], (int64_t)pSrc[0], (int64_t)pSrc[1], pi64Dst[0], pi64Dst[1])); \
     561            pi64Dst  += 2; \
     562            pSrc     += 2; \
     563        } \
     564    } \
     565    \
     566    /* 2ch -> 1ch */ \
     567    static DECLCALLBACK(void) RT_CONCAT(audioMixBufDecode2ChTo1Ch,a_Name)(int64_t *pi64Dst, void const *pvSrc, uint32_t cFrames, \
     568                                                                          PAUDIOMIXBUFWRITESTATE pState) \
     569    { \
     570        RT_NOREF_PV(pState); \
     571        a_Type const *pSrc = (a_Type const *)pvSrc; \
     572        while (cFrames-- > 0) \
     573        { \
     574            pi64Dst[0] = (audioMixBufClipFrom##a_Name(pSrc[0]) + audioMixBufClipFrom##a_Name(pSrc[1])) / 2; \
     575            pi64Dst  += 2; /** @todo when we do multi channel mixbuf support, this can change to 1 */ \
     576            pSrc     += 2; \
     577        } \
     578    } \
     579    \
     580    /* 1ch -> 2ch */ \
     581    static DECLCALLBACK(void) RT_CONCAT(audioMixBufDecode1ChTo2Ch,a_Name)(int64_t *pi64Dst, void const *pvSrc, uint32_t cFrames, \
     582                                                                          PAUDIOMIXBUFWRITESTATE pState) \
     583    { \
     584        RT_NOREF_PV(pState); \
     585        a_Type const *pSrc = (a_Type const *)pvSrc; \
     586        while (cFrames-- > 0) \
     587        { \
     588            pi64Dst[1] = pi64Dst[0] = audioMixBufClipFrom##a_Name(pSrc[0]); \
     589            pi64Dst  += 2; \
     590            pSrc     += 1; \
     591        } \
     592    } \
     593    \
     594    /* 1ch -> 1ch */ \
     595    static DECLCALLBACK(void) RT_CONCAT(audioMixBufDecode1ChTo1Ch,a_Name)(int64_t *pi64Dst, void const *pvSrc, uint32_t cFrames, \
     596                                                                          PAUDIOMIXBUFWRITESTATE pState) \
     597    { \
     598        RT_NOREF_PV(pState); \
     599        a_Type const *pSrc = (a_Type const *)pvSrc; \
     600        while (cFrames-- > 0) \
     601        { \
     602            pi64Dst[0] = audioMixBufClipFrom##a_Name(pSrc[0]); \
     603            pi64Dst  += 2; /** @todo when we do multi channel mixbuf support, this can change to 1 */ \
     604            pSrc     += 1; \
     605        } \
     606    }
    547607
    548608/* audioMixBufConvXXXS8: 8 bit, signed. */
     
    589649}
    590650
     651/* Encoders for peek: */
    591652
    592653static DECLCALLBACK(void)
     
    635696         pi64Dst += 1;
    636697         pi64Src += 2;
     698    }
     699}
     700
     701
     702/* Decoders for write: */
     703
     704static DECLCALLBACK(void)
     705audioMixBufDecode2ChTo2ChRaw(int64_t *pi64Dst, void const *pvSrc, uint32_t cFrames, PAUDIOMIXBUFWRITESTATE pState)
     706{
     707    RT_NOREF_PV(pState);
     708    memcpy(pi64Dst, pvSrc, sizeof(int64_t) * 2 * cFrames);
     709}
     710
     711static DECLCALLBACK(void)
     712audioMixBufDecode2ChTo1ChRaw(int64_t *pi64Dst, void const *pvSrc, uint32_t cFrames, PAUDIOMIXBUFWRITESTATE pState)
     713{
     714    RT_NOREF_PV(pState);
     715    int64_t const *pi64Src = (int64_t const *)pvSrc;
     716    while (cFrames-- > 0)
     717    {
     718         *pi64Dst = (pi64Src[0] + pi64Src[1]) / 2;
     719         pi64Dst += 2;  /** @todo when we do multi channel mixbuf support, this can change to 1 */
     720         pi64Src += 2;
     721    }
     722}
     723
     724static DECLCALLBACK(void)
     725audioMixBufDecode1ChTo2ChRaw(int64_t *pi64Dst, void const *pvSrc, uint32_t cFrames, PAUDIOMIXBUFWRITESTATE pState)
     726{
     727    RT_NOREF_PV(pState);
     728    int64_t const *pi64Src = (int64_t const *)pvSrc;
     729    while (cFrames-- > 0)
     730    {
     731         pi64Dst[0] = pi64Dst[1] = *pi64Src;
     732         pi64Dst += 2;
     733         pi64Src += 1;
     734    }
     735}
     736
     737static DECLCALLBACK(void)
     738audioMixBufDecode1ChTo1ChRaw(int64_t *pi64Dst, void const *pvSrc, uint32_t cFrames, PAUDIOMIXBUFWRITESTATE pState)
     739{
     740    RT_NOREF_PV(pState);
     741    /** @todo memcpy(pi64Dst, pvSrc, sizeof(int64_t) * 1 * cFrames); when we do
     742     *        multi channel mixbuf support. */
     743    int64_t const *pi64Src = (int64_t const *)pvSrc;
     744    while (cFrames-- > 0)
     745    {
     746         *pi64Dst = *pi64Src;
     747         pi64Dst += 2; /** @todo when we do multi channel mixbuf support, this can change to 1 */
     748         pi64Src += 1;
    637749    }
    638750}
     
    15291641
    15301642/**
    1531  * Reads audio frames at a specific offset.
    1532  *
    1533  * @returns VBox status code.
    1534  * @param   pMixBuf                 Mixing buffer to read audio frames from.
    1535  * @param   offFrames               Offset (in audio frames) to start reading from.
    1536  * @param   pvBuf                   Pointer to buffer to write output to.
    1537  * @param   cbBuf                   Size (in bytes) of buffer to write to.
    1538  * @param   pcbRead                 Size (in bytes) of data read. Optional.
    1539  */
    1540 int AudioMixBufReadAt(PAUDIOMIXBUF pMixBuf, uint32_t offFrames, void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead)
    1541 {
    1542     return AudioMixBufReadAtEx(pMixBuf, &pMixBuf->Props, offFrames, pvBuf, cbBuf, pcbRead);
    1543 }
    1544 
    1545 /**
    1546  * Reads audio frames at a specific offset.
    1547  * If the audio format of the mixing buffer and the requested audio format do
    1548  * not match the output will be converted accordingly.
    1549  *
    1550  * @returns VBox status code.
    1551  * @param   pMixBuf     Mixing buffer to read audio frames from.
    1552  * @param   pDstProps   The target format.
    1553  * @param   offFrames   Offset (in audio frames) to start reading from.
    1554  * @param   pvBuf       Pointer to buffer to write output to.
    1555  * @param   cbBuf       Size (in bytes) of buffer to write to.
    1556  * @param   pcbRead     Size (in bytes) of data read. Optional.
    1557  */
    1558 int AudioMixBufReadAtEx(PAUDIOMIXBUF pMixBuf, PCPDMAUDIOPCMPROPS pDstProps,
    1559                         uint32_t offFrames, void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead)
    1560 {
    1561     AssertPtrReturn(pMixBuf, VERR_INVALID_POINTER);
    1562     AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
    1563     /* pcbRead is optional. */
    1564 
    1565     uint32_t cDstFrames = pMixBuf->cFrames;
    1566     uint32_t cLive = pMixBuf->cUsed;
    1567 
    1568     uint32_t cDead = cDstFrames - cLive;
    1569     uint32_t cToProcess = (uint32_t)AUDIOMIXBUF_F2F_RATIO(pMixBuf, cDead);
    1570     cToProcess = RT_MIN(cToProcess, AUDIOMIXBUF_B2F(pMixBuf, cbBuf));
    1571 
    1572     AUDMIXBUF_LOG(("%s: offFrames=%RU32, cLive=%RU32, cDead=%RU32, cToProcess=%RU32\n",
    1573                    pMixBuf->pszName, offFrames, cLive, cDead, cToProcess));
    1574 
    1575     int rc;
    1576     if (cToProcess)
    1577     {
    1578         PFNAUDIOMIXBUFCONVTO pfnConvTo = NULL;
    1579         if (PDMAudioPropsAreEqual(&pMixBuf->Props, pDstProps))
    1580             pfnConvTo = pMixBuf->pfnConvTo;
    1581         else
    1582             pfnConvTo = audioMixBufConvToLookup(pDstProps);
    1583         if (pfnConvTo)
    1584         {
    1585             AUDMIXBUFCONVOPTS convOpts;
    1586             RT_ZERO(convOpts);
    1587             /* Note: No volume handling/conversion done in the conversion-to macros (yet). */
    1588 
    1589             convOpts.cFrames = cToProcess;
    1590 
    1591             pfnConvTo(pvBuf, pMixBuf->pFrames + offFrames, &convOpts);
    1592 
    1593 #ifdef DEBUG
    1594             AudioMixBufDbgPrint(pMixBuf);
    1595 #endif
    1596             rc = VINF_SUCCESS;
    1597         }
    1598         else
    1599         {
    1600             AssertFailed();
    1601             rc = VERR_NOT_SUPPORTED;
    1602         }
    1603     }
    1604     else
    1605         rc = VINF_SUCCESS;
    1606 
    1607     if (RT_SUCCESS(rc))
    1608     {
    1609         if (pcbRead)
    1610             *pcbRead = AUDIOMIXBUF_F2B(pMixBuf, cToProcess);
    1611     }
    1612 
    1613     AUDMIXBUF_LOG(("cbRead=%RU32, rc=%Rrc\n", AUDIOMIXBUF_F2B(pMixBuf, cToProcess), rc));
    1614     return rc;
    1615 }
    1616 
    1617 /**
    16181643 * Reads audio frames. The audio format of the mixing buffer will be used.
    16191644 *
     
    18661891
    18671892/**
     1893 * Resets the resampling state unconditionally.
     1894 *
     1895 * @param   pRate   The state to reset.
     1896 */
     1897static void audioMixBufRateResetAlways(PAUDIOSTREAMRATE pRate)
     1898{
     1899    pRate->offDst = 0;
     1900    pRate->offSrc = 0;
     1901    for (uintptr_t i = 0; i < RT_ELEMENTS(pRate->SrcLast.ai64Samples); i++)
     1902        pRate->SrcLast.ai64Samples[0] = 0;
     1903}
     1904
     1905
     1906/**
     1907 * Resets the resampling state.
     1908 *
     1909 * @param   pRate   The state to reset.
     1910 */
     1911DECLINLINE(void) audioMixBufRateReset(PAUDIOSTREAMRATE pRate)
     1912{
     1913    if (pRate->offDst == 0)
     1914    { /* likely */ }
     1915    else
     1916    {
     1917        Assert(!pRate->fNoConversionNeeded);
     1918        audioMixBufRateResetAlways(pRate);
     1919    }
     1920}
     1921
     1922
     1923/**
     1924 * Initializes the frame rate converter state.
     1925 *
     1926 * @returns VBox status code.
     1927 * @param   pRate       The state to initialize.
     1928 * @param   uSrcHz      The source frame rate.
     1929 * @param   uDstHz      The destination frame rate.
     1930 * @param   cChannels   The number of channels in a frame.
     1931 */
     1932DECLINLINE(int) audioMixBufRateInit(PAUDIOSTREAMRATE pRate, uint32_t uSrcHz, uint32_t uDstHz, uint8_t cChannels)
     1933{
     1934    /*
     1935     * Do we need to set up frequency conversion?
     1936     *
     1937     * Some examples to get an idea of what uDstInc holds:
     1938     *   44100 to 44100 -> (44100<<32) / 44100 = 0x01'00000000 (4294967296)
     1939     *   22050 to 44100 -> (22050<<32) / 44100 = 0x00'80000000 (2147483648)
     1940     *   44100 to 22050 -> (44100<<32) / 22050 = 0x02'00000000 (8589934592)
     1941     *   44100 to 48000 -> (44100<<32) / 48000 = 0x00'EB333333 (3946001203.2)
     1942     *   48000 to 44100 -> (48000<<32) / 44100 = 0x01'16A3B35F (4674794335.7823129251700680272109)
     1943     */
     1944    audioMixBufRateResetAlways(pRate);
     1945    if (uSrcHz == uDstHz)
     1946    {
     1947        pRate->fNoConversionNeeded = true;
     1948        pRate->uDstInc             = RT_BIT_64(32);
     1949        pRate->pfnResample         = NULL;
     1950    }
     1951    else
     1952    {
     1953        pRate->fNoConversionNeeded = false;
     1954        pRate->uDstInc             = ((uint64_t)uSrcHz << 32) / uDstHz;
     1955        AssertReturn(uSrcHz != 0, VERR_INVALID_PARAMETER);
     1956        switch (cChannels)
     1957        {
     1958            case 1: pRate->pfnResample = audioMixBufResample1ChGeneric; break;
     1959            case 2: pRate->pfnResample = audioMixBufResample2ChGeneric; break;
     1960            default:
     1961                AssertMsgFailedReturn(("resampling %u changes is not implemented yet\n", cChannels), VERR_OUT_OF_RANGE);
     1962        }
     1963    }
     1964    return VINF_SUCCESS;
     1965}
     1966
     1967
     1968
     1969/**
    18681970 * Initializes the peek state, setting up encoder and (if necessary) resampling.
    18691971 *
     
    19822084                AssertMsgFailedReturn(("from %u to %u channels is not implemented yet\n", cSrcCh, cDstCh), VERR_OUT_OF_RANGE);
    19832085        }
    1984 
    1985     }
     2086    }
     2087
     2088    int rc = audioMixBufRateInit(&pState->Rate, PDMAudioPropsHz(&pMixBuf->Props), PDMAudioPropsHz(pProps), cSrcCh);
     2089    AUDMIXBUF_LOG(("%s: %RU32 Hz to %RU32 Hz => uDstInc=0x%'RX64\n", pMixBuf->pszName, PDMAudioPropsHz(&pMixBuf->Props),
     2090                   PDMAudioPropsHz(pProps), pState->Rate.uDstInc));
     2091    return rc;
     2092}
     2093
     2094
     2095/**
     2096 * Initializes the write/blend state, setting up decoders and (if necessary)
     2097 * resampling.
     2098 *
     2099 * @returns VBox status code.
     2100 */
     2101int AudioMixBufInitWriteState(PCAUDIOMIXBUF pMixBuf, PAUDIOMIXBUFWRITESTATE pState, PCPDMAUDIOPCMPROPS pProps)
     2102{
     2103    AssertPtr(pMixBuf);
     2104    AssertPtr(pState);
     2105    AssertPtr(pProps);
    19862106
    19872107    /*
    1988      * Do we need to set up frequency conversion?
    1989      *
    1990      * Some examples to get an idea of what uDstInc holds:
    1991      *   44100 to 44100 -> (44100<<32) / 44100 = 0x01'00000000 (4294967296)
    1992      *   22050 to 44100 -> (22050<<32) / 44100 = 0x00'80000000 (2147483648)
    1993      *   44100 to 22050 -> (44100<<32) / 22050 = 0x02'00000000 (8589934592)
    1994      *   44100 to 48000 -> (44100<<32) / 48000 = 0x00'EB333333 (3946001203.2)
    1995      *   48000 to 44100 -> (48000<<32) / 44100 = 0x01'16A3B35F (4674794335.7823129251700680272109)
     2108     * Pick the encoding function first.
    19962109     */
    1997     uint32_t const uSrcHz = PDMAudioPropsHz(&pMixBuf->Props);
    1998     uint32_t const uDstHz = PDMAudioPropsHz(pProps);
    1999     RT_ZERO(pState->Rate);
    2000     if (uSrcHz == uDstHz)
    2001     {
    2002         pState->Rate.fNoConversionNeeded = true;
    2003         pState->Rate.uDstInc             = RT_BIT_64(32);
    2004         pState->Rate.pfnResample         = NULL;
     2110    uint8_t const cSrcCh = PDMAudioPropsChannels(pProps);
     2111    uint8_t const cDstCh = PDMAudioPropsChannels(&pMixBuf->Props);
     2112    pState->cSrcChannels = cSrcCh;
     2113    pState->cDstChannels = cDstCh;
     2114    pState->cbSrcFrame   = PDMAudioPropsFrameSize(pProps);
     2115    if (PDMAudioPropsIsSigned(pProps))
     2116    {
     2117        switch (cDstCh)
     2118        {
     2119            case 1:
     2120                AssertReturn(cSrcCh == 1 || cSrcCh == 2, VERR_OUT_OF_RANGE);
     2121                switch (PDMAudioPropsSampleSize(pProps))
     2122                {
     2123                    case 1:
     2124                        pState->pfnDecode = cSrcCh == 1 ? audioMixBufDecode1ChTo1ChS8  : audioMixBufDecode2ChTo1ChS8;
     2125                        break;
     2126                    case 2:
     2127                        pState->pfnDecode = cSrcCh == 1 ? audioMixBufDecode1ChTo1ChS16 : audioMixBufDecode2ChTo1ChS16;
     2128                        break;
     2129                    case 4:
     2130                        pState->pfnDecode = cSrcCh == 1 ? audioMixBufDecode1ChTo1ChS32 : audioMixBufDecode2ChTo1ChS32;
     2131                        break;
     2132                    case 8:
     2133                        AssertReturn(pProps->fRaw, VERR_DISK_INVALID_FORMAT);
     2134                        pState->pfnDecode = cSrcCh == 1 ? audioMixBufDecode1ChTo1ChRaw : audioMixBufDecode2ChTo1ChRaw;
     2135                        break;
     2136                    default:
     2137                        AssertMsgFailedReturn(("%u bytes\n", PDMAudioPropsSampleSize(pProps)), VERR_OUT_OF_RANGE);
     2138                }
     2139                break;
     2140            case 2:
     2141                AssertReturn(cSrcCh == 1 || cSrcCh == 2, VERR_OUT_OF_RANGE);
     2142                switch (PDMAudioPropsSampleSize(pProps))
     2143                {
     2144                    case 1:
     2145                        pState->pfnDecode = cSrcCh == 1 ? audioMixBufDecode1ChTo2ChS8  : audioMixBufDecode2ChTo2ChS8;
     2146                        break;
     2147                    case 2:
     2148                        pState->pfnDecode = cSrcCh == 1 ? audioMixBufDecode1ChTo2ChS16 : audioMixBufDecode2ChTo2ChS16;
     2149                        break;
     2150                    case 4:
     2151                        pState->pfnDecode = cSrcCh == 1 ? audioMixBufDecode1ChTo2ChS32 : audioMixBufDecode2ChTo2ChS32;
     2152                        break;
     2153                    case 8:
     2154                        AssertReturn(pProps->fRaw, VERR_DISK_INVALID_FORMAT);
     2155                        pState->pfnDecode = cSrcCh == 1 ? audioMixBufDecode1ChTo2ChRaw : audioMixBufDecode2ChTo2ChRaw;
     2156                        break;
     2157                    default:
     2158                        AssertMsgFailedReturn(("%u bytes\n", PDMAudioPropsSampleSize(pProps)), VERR_OUT_OF_RANGE);
     2159                }
     2160                break;
     2161            default:
     2162                /* Note: We may have dedicated encoders for a few selected multichannel
     2163                         configurations, and generic ones that encodes channel by channel (i.e.
     2164                         add the mixer channel count, destination frame size, and an array of
     2165                         destination channel frame offsets to the state). */
     2166                AssertMsgFailedReturn(("from %u to %u channels is not implemented yet\n", cSrcCh, cDstCh), VERR_OUT_OF_RANGE);
     2167        }
    20052168    }
    20062169    else
    20072170    {
    2008         AssertReturn(uSrcHz != 0, VERR_INVALID_PARAMETER);
    2009         pState->Rate.fNoConversionNeeded = false;
    2010         pState->Rate.uDstInc             = ((uint64_t)uSrcHz << 32) / uDstHz;
    2011         switch (cSrcCh)
     2171        switch (cDstCh)
    20122172        {
    2013             case 1: pState->Rate.pfnResample = audioMixBufResample1ChGeneric; break;
    2014             case 2: pState->Rate.pfnResample = audioMixBufResample2ChGeneric; break;
     2173            case 1:
     2174                AssertReturn(cSrcCh == 1 || cSrcCh == 2, VERR_OUT_OF_RANGE);
     2175                switch (PDMAudioPropsSampleSize(pProps))
     2176                {
     2177                    case 1:
     2178                        pState->pfnDecode = cSrcCh == 1 ? audioMixBufDecode1ChTo1ChU8  : audioMixBufDecode2ChTo1ChU8;
     2179                        break;
     2180                    case 2:
     2181                        pState->pfnDecode = cSrcCh == 1 ? audioMixBufDecode1ChTo1ChU16 : audioMixBufDecode2ChTo1ChU16;
     2182                        break;
     2183                    case 4:
     2184                        pState->pfnDecode = cSrcCh == 1 ? audioMixBufDecode1ChTo1ChU32 : audioMixBufDecode2ChTo1ChU32;
     2185                        break;
     2186                    default:
     2187                        AssertMsgFailedReturn(("%u bytes\n", PDMAudioPropsSampleSize(pProps)), VERR_OUT_OF_RANGE);
     2188                }
     2189                break;
     2190            case 2:
     2191                AssertReturn(cSrcCh == 1 || cSrcCh == 2, VERR_OUT_OF_RANGE);
     2192                switch (PDMAudioPropsSampleSize(pProps))
     2193                {
     2194                    case 1:
     2195                        pState->pfnDecode = cSrcCh == 1 ? audioMixBufDecode1ChTo2ChU8  : audioMixBufDecode2ChTo2ChU8;
     2196                        break;
     2197                    case 2:
     2198                        pState->pfnDecode = cSrcCh == 1 ? audioMixBufDecode1ChTo2ChU16 : audioMixBufDecode2ChTo2ChU16;
     2199                        break;
     2200                    case 4:
     2201                        pState->pfnDecode = cSrcCh == 1 ? audioMixBufDecode1ChTo2ChU32 : audioMixBufDecode2ChTo2ChU32;
     2202                        break;
     2203                    default:
     2204                        AssertMsgFailedReturn(("%u bytes\n", PDMAudioPropsSampleSize(pProps)), VERR_OUT_OF_RANGE);
     2205                }
     2206                break;
    20152207            default:
    2016                 AssertMsgFailedReturn(("resampling %u changes is not implemented yet\n", cSrcCh), VERR_OUT_OF_RANGE);
     2208                /* Note: We may have dedicated encoders for a few selected multichannel
     2209                         configurations, and generic ones that encodes channel by channel (i.e.
     2210                         add an array of destination channel frame offsets to the state). */
     2211                AssertMsgFailedReturn(("from %u to %u channels is not implemented yet\n", cSrcCh, cDstCh), VERR_OUT_OF_RANGE);
    20172212        }
    20182213    }
    2019     AUDMIXBUF_LOG(("%s: %RU32 Hz to %RU32 Hz => uDstInc=0x%'RX64\n", pMixBuf->pszName, uSrcHz, uDstHz, pState->Rate.uDstInc));
    2020     return VINF_SUCCESS;
     2214
     2215    int rc = audioMixBufRateInit(&pState->Rate, PDMAudioPropsHz(pProps), PDMAudioPropsHz(&pMixBuf->Props), cDstCh);
     2216    AUDMIXBUF_LOG(("%s: %RU32 Hz to %RU32 Hz => uDstInc=0x%'RX64\n", pMixBuf->pszName, PDMAudioPropsHz(pProps),
     2217                   PDMAudioPropsHz(&pMixBuf->Props), pState->Rate.uDstInc));
     2218    return rc;
    20212219}
    20222220
     
    20382236        uint32_t cMaxDstFrames = RT_MIN(RT_ELEMENTS(ai64DstRate) / pState->cDstChannels, cbDst / pState->cbDstFrame);
    20392237        uint32_t const cDstFrames = pState->Rate.pfnResample(ai64DstRate, cMaxDstFrames,
    2040                                                             &pMixBuf->pFrames[offSrcFrame].i64LSample, cSrcFrames, &cSrcFrames,
    2041                                                             &pState->Rate);
     2238                                                             &pMixBuf->pFrames[offSrcFrame].i64LSample, cSrcFrames, &cSrcFrames,
     2239                                                             &pState->Rate);
    20422240        *pcSrcFramesPeeked += cSrcFrames;
    20432241        cMaxSrcFrames      -= cSrcFrames;
     
    20522250    }
    20532251}
    2054 
    20552252
    20562253
     
    21232320
    21242321/**
     2322 * Worker for AudioMixBufPeek that handles the rate conversion case.
     2323 */
     2324DECL_NO_INLINE(static, void)
     2325AudioMixBufWriteResampling(PAUDIOMIXBUF pMixBuf, PAUDIOMIXBUFWRITESTATE pState, const void *pvSrcBuf, uint32_t cbSrcBuf,
     2326                           uint32_t offDstFrame, uint32_t cMaxDstFrames, uint32_t *pcDstFramesWritten)
     2327{
     2328    *pcDstFramesWritten = 0;
     2329    while (cMaxDstFrames > 0 && cbSrcBuf >= pState->cbSrcFrame)
     2330    {
     2331        /* Decode into temporary buffer. */
     2332        int64_t  ai64SrcDecoded[1024];
     2333        uint32_t cFramesDecoded = RT_MIN(RT_ELEMENTS(ai64SrcDecoded) / pState->cSrcChannels, cbSrcBuf / pState->cbSrcFrame);
     2334        pState->pfnDecode(ai64SrcDecoded, pvSrcBuf, cFramesDecoded, pState);
     2335        cbSrcBuf -= cFramesDecoded * pState->cbSrcFrame;
     2336        pvSrcBuf  = (uint8_t const *)pvSrcBuf + cFramesDecoded * pState->cbSrcFrame;
     2337
     2338        /* Rate convert that into the mixer. */
     2339        uint32_t iFrameDecoded = 0;
     2340        while (iFrameDecoded < cFramesDecoded)
     2341        {
     2342            uint32_t cDstMaxFrames    = RT_MIN(pMixBuf->cFrames - offDstFrame, cMaxDstFrames);
     2343            uint32_t cSrcFrames       = cFramesDecoded - iFrameDecoded;
     2344            uint32_t const cDstFrames = pState->Rate.pfnResample(&pMixBuf->pFrames[offDstFrame].i64LSample, cDstMaxFrames,
     2345                                                                 &ai64SrcDecoded[iFrameDecoded * pState->cSrcChannels],
     2346                                                                 cSrcFrames, &cSrcFrames, &pState->Rate);
     2347
     2348            iFrameDecoded       += cSrcFrames;
     2349            *pcDstFramesWritten += cDstFrames;
     2350            offDstFrame          = (offDstFrame + cDstFrames) % pMixBuf->cFrames;
     2351        }
     2352    }
     2353
     2354    /** @todo How to squeeze odd frames out of 22050 => 44100 conversion?   */
     2355}
     2356
     2357
     2358/**
     2359 * Writes @a cbSrcBuf bytes to the mixer buffer starting at @a offDstFrame,
     2360 * converting it as needed, leaving the write offset untouched.
     2361 *
     2362 * @param   pMixBuf             The mixing buffer.
     2363 * @param   pState              Source configuration & conversion state.
     2364 * @param   pvSrcBuf            The source frames.
     2365 * @param   cbSrcBuf            Number of bytes of source frames.  This will be
     2366 *                              convered in full.
     2367 * @param   offDstFrame         Mixing buffer offset relative to the write
     2368 *                              position.
     2369 * @param   cMaxDstFrames       Max number of frames to write.
     2370 * @param   pcDstFramesWritten  Where to return the number of frames actually
     2371 *                              written.
     2372 *
     2373 * @note    Does not advance the write position, please call AudioMixBufCommit()
     2374 *          to do that.
     2375 */
     2376void AudioMixBufWrite(PAUDIOMIXBUF pMixBuf, PAUDIOMIXBUFWRITESTATE pState, const void *pvSrcBuf, uint32_t cbSrcBuf,
     2377                      uint32_t offDstFrame, uint32_t cMaxDstFrames, uint32_t *pcDstFramesWritten)
     2378{
     2379    /*
     2380     * Check inputs.
     2381     */
     2382    AssertPtr(pMixBuf);
     2383    Assert(pMixBuf->uMagic == AUDIOMIXBUF_MAGIC);
     2384    AssertPtr(pState);
     2385    AssertPtr(pState->pfnDecode);
     2386    Assert(pState->cDstChannels == PDMAudioPropsChannels(&pMixBuf->Props));
     2387    Assert(cMaxDstFrames > 0);
     2388    Assert(cMaxDstFrames <= pMixBuf->cFrames - pMixBuf->cUsed);
     2389    Assert(offDstFrame <= pMixBuf->cFrames);
     2390    AssertPtr(pcDstFramesWritten);
     2391    AssertPtr(pvSrcBuf);
     2392    Assert(!(cbSrcBuf % pState->cbSrcFrame));
     2393    AssertPtr(pcDstFramesWritten);
     2394
     2395    /*
     2396     * Make start frame absolute.
     2397     */
     2398    offDstFrame = (pMixBuf->offWrite + offDstFrame) % pMixBuf->cFrames;
     2399
     2400    /*
     2401     * Hopefully no sample rate conversion is necessary...
     2402     */
     2403    if (pState->Rate.fNoConversionNeeded)
     2404    {
     2405        /* Figure out how much we should convert. */
     2406        Assert(cMaxDstFrames >= cbSrcBuf / pState->cbSrcFrame);
     2407        cMaxDstFrames       = RT_MIN(cMaxDstFrames, cbSrcBuf / pState->cbSrcFrame);
     2408        *pcDstFramesWritten = cMaxDstFrames;
     2409
     2410        /* First chunk. */
     2411        uint32_t const cDstFrames1 = RT_MIN(pMixBuf->cFrames - offDstFrame, cMaxDstFrames);
     2412        pState->pfnDecode(&pMixBuf->pFrames[offDstFrame].i64LSample, pvSrcBuf, cDstFrames1, pState);
     2413
     2414        /* Another chunk from the start of the mixing buffer? */
     2415        if (cMaxDstFrames > cDstFrames1)
     2416            pState->pfnDecode(&pMixBuf->pFrames[0].i64LSample, (uint8_t *)pvSrcBuf + cDstFrames1 * pState->cbSrcFrame,
     2417                              cMaxDstFrames - cDstFrames1, pState);
     2418    }
     2419    else
     2420        AudioMixBufWriteResampling(pMixBuf, pState, pvSrcBuf, cbSrcBuf, offDstFrame, cMaxDstFrames, pcDstFramesWritten);
     2421}
     2422
     2423
     2424/**
     2425 * @todo not sure if 'blend' is the appropriate term here, but you know what
     2426 *       we mean.
     2427 */
     2428void AudioMixBufBlend(PAUDIOMIXBUF pMixBuf, PAUDIOMIXBUFWRITESTATE pState, const void *pvSrcBuf, uint32_t cbSrcBuf,
     2429                      uint32_t offDstFrame, uint32_t cMaxDstFrames, uint32_t *pcDstFramesBlended)
     2430{
     2431    /** @todo */
     2432    RT_NOREF(pMixBuf, pState, pvSrcBuf, cbSrcBuf, offDstFrame, cMaxDstFrames, pcDstFramesBlended);
     2433}
     2434
     2435
     2436/**
     2437 * Writes @a cFrames of silence at @a offFrame relative to current write pos.
     2438 *
     2439 * This will also adjust the resampling state.
     2440 *
     2441 * @param   pMixBuf     The mixing buffer.
     2442 * @param   pState      The write state.
     2443 * @param   offFrames   Where to start writing silence relative to the current
     2444 *                      write position.
     2445 * @param   cFrames     Number of frames of silence.
     2446 * @sa      AudioMixBufSilence
     2447 *
     2448 * @note    Does not advance the write position, please call AudioMixBufCommit()
     2449 *          to do that.
     2450 */
     2451void AudioMixBufSilence(PAUDIOMIXBUF pMixBuf, PAUDIOMIXBUFWRITESTATE pState, uint32_t offFrame, uint32_t cFrames)
     2452{
     2453    /*
     2454     * Check inputs.
     2455     */
     2456    AssertPtr(pMixBuf);
     2457    Assert(pMixBuf->uMagic == AUDIOMIXBUF_MAGIC);
     2458    AssertPtr(pState);
     2459    AssertPtr(pState->pfnDecode);
     2460    Assert(pState->cDstChannels == PDMAudioPropsChannels(&pMixBuf->Props));
     2461    Assert(cFrames > 0);
     2462    Assert(cFrames <= pMixBuf->cFrames);
     2463    Assert(offFrame <= pMixBuf->cFrames);
     2464    Assert(offFrame + cFrames <= pMixBuf->cUsed);
     2465
     2466    /*
     2467     * Make start frame absolute.
     2468     */
     2469    offFrame = (pMixBuf->offWrite + offFrame) % pMixBuf->cFrames;
     2470
     2471    /*
     2472     * First chunk.
     2473     */
     2474    uint32_t cChunk = RT_MIN(pMixBuf->cFrames - offFrame, cFrames);
     2475    RT_BZERO(&pMixBuf->pFrames[offFrame], cChunk * sizeof(pMixBuf->pFrames[0]));
     2476    cFrames -= cChunk;
     2477
     2478    /*
     2479     * Second chunk, if needed.
     2480     */
     2481    if (cFrames > 0)
     2482    {
     2483        AssertStmt(cFrames <= pMixBuf->cFrames, cFrames = pMixBuf->cFrames);
     2484        RT_BZERO(&pMixBuf->pFrames[0], cFrames * sizeof(pMixBuf->pFrames[0]));
     2485    }
     2486
     2487    /*
     2488     * Reset the resampling state.
     2489     */
     2490    audioMixBufRateReset(&pState->Rate);
     2491}
     2492
     2493
     2494/**
     2495 * Records a blending gap (silence) of @a cFrames.
     2496 *
     2497 * This is used to adjust or reset the resampling state so we start from a
     2498 * silence state the next time we need to blend or write using @a pState.
     2499 *
     2500 * @param   pMixBuf     The mixing buffer.
     2501 * @param   pState      The write state.
     2502 * @param   cFrames     Number of frames of silence.
     2503 * @sa      AudioMixBufSilence
     2504 */
     2505void AudioMixBufBlendGap(PAUDIOMIXBUF pMixBuf, PAUDIOMIXBUFWRITESTATE pState, uint32_t cFrames)
     2506{
     2507    /*
     2508     * For now we'll just reset the resampling state regardless of how many
     2509     * frames of silence there is.
     2510     */
     2511    audioMixBufRateReset(&pState->Rate);
     2512    RT_NOREF(pMixBuf, cFrames);
     2513}
     2514
     2515
     2516/**
    21252517 * Advances the read position of the buffer.
    21262518 *
     
    21292521 * @param   pMixBuf     The mixing buffer.
    21302522 * @param   cFrames     Number of frames to advance.
     2523 * @sa      AudioMixBufCommit
    21312524 */
    21322525void AudioMixBufAdvance(PAUDIOMIXBUF pMixBuf, uint32_t cFrames)
     
    21392532    pMixBuf->offRead  = (pMixBuf->offRead + cFrames) % pMixBuf->cFrames;
    21402533    LogFlowFunc(("%s: Advanced %u frames: offRead=%u cUsed=%u\n", pMixBuf->pszName, cFrames, pMixBuf->offRead, pMixBuf->cUsed));
     2534}
     2535
     2536
     2537/**
     2538 * Advances the write position of the buffer.
     2539 *
     2540 * For use after done peeking with AudioMixBufWrite(), AudioMixBufSilence(),
     2541 * AudioMixBufBlend() and AudioMixBufBlendGap().
     2542 *
     2543 * @param   pMixBuf     The mixing buffer.
     2544 * @param   cFrames     Number of frames to advance.
     2545 * @sa      AudioMixBufAdvance
     2546 */
     2547void AudioMixBufCommit(PAUDIOMIXBUF pMixBuf, uint32_t cFrames)
     2548{
     2549    AssertPtrReturnVoid(pMixBuf);
     2550    AssertReturnVoid(pMixBuf->uMagic == AUDIOMIXBUF_MAGIC);
     2551
     2552    AssertStmt(cFrames <= pMixBuf->cFrames - pMixBuf->cUsed, cFrames = pMixBuf->cFrames - pMixBuf->cUsed);
     2553    pMixBuf->cUsed   += cFrames;
     2554    pMixBuf->offWrite = (pMixBuf->offWrite + cFrames) % pMixBuf->cFrames;
     2555    LogFlowFunc(("%s: Advanced %u frames: offWrite=%u cUsed=%u\n", pMixBuf->pszName, cFrames, pMixBuf->offWrite, pMixBuf->cUsed));
    21412556}
    21422557
  • trunk/src/VBox/Devices/Audio/AudioMixBuffer.h

    r88433 r89302  
    159159    /** Source (mixer) channels. */
    160160    uint8_t                     cSrcChannels;
    161     /** Destination (mixer) channels. */
     161    /** Destination channels. */
    162162    uint8_t                     cDstChannels;
    163163    /** Destination frame size. */
     
    166166/** Pointer to peek state & config. */
    167167typedef AUDIOMIXBUFPEEKSTATE *PAUDIOMIXBUFPEEKSTATE;
     168
     169
     170/**
     171 * State & config for AudioMixBufWrite, AudioMixBufSilence, AudioMixBufBlend and
     172 * AudioMixBufBlendGap, created by AudioMixBufInitWriteState.
     173 */
     174typedef struct AUDIOMIXBUFWRITESTATE
     175{
     176    /** Encodes @a cFrames from @a pvSrc to @a paDst. */
     177    DECLR3CALLBACKMEMBER(void,  pfnDecode,(int64_t *paDst, const void *pvSrc, uint32_t cFrames, struct AUDIOMIXBUFWRITESTATE *pState));
     178    /** Encodes @a cFrames from @a pvSrc blending into @a paDst. */
     179    DECLR3CALLBACKMEMBER(void,  pfnDecodeBlend,(int64_t *paDst, const void *pvSrc, uint32_t cFrames, struct AUDIOMIXBUFWRITESTATE *pState));
     180    /** Sample rate conversion state (only used when needed). */
     181    AUDIOSTREAMRATE             Rate;
     182    /** Destination (mixer) channels. */
     183    uint8_t                     cDstChannels;
     184    /** Source hannels. */
     185    uint8_t                     cSrcChannels;
     186    /** Source frame size. */
     187    uint8_t                     cbSrcFrame;
     188} AUDIOMIXBUFWRITESTATE;
     189/** Pointer to write state & config. */
     190typedef AUDIOMIXBUFWRITESTATE *PAUDIOMIXBUFWRITESTATE;
    168191
    169192
     
    279302void    AudioMixBufDrop(PAUDIOMIXBUF pMixBuf);
    280303
     304int     AudioMixBufInitWriteState(PCAUDIOMIXBUF pMixBuf, PAUDIOMIXBUFWRITESTATE pState, PCPDMAUDIOPCMPROPS pSrcProps);
     305void    AudioMixBufWrite(PAUDIOMIXBUF pMixBuf, PAUDIOMIXBUFWRITESTATE pState, const void *pvSrcBuf, uint32_t cbSrcBuf,
     306                         uint32_t offDstFrame, uint32_t cMaxDstFrames, uint32_t *pcDstFramesWritten);
     307void    AudioMixBufSilence(PAUDIOMIXBUF pMixBuf, PAUDIOMIXBUFWRITESTATE pState, uint32_t offFrame, uint32_t cFrames);
     308void    AudioMixBufBlend(PAUDIOMIXBUF pMixBuf, PAUDIOMIXBUFWRITESTATE pState, const void *pvSrcBuf, uint32_t cbSrcBuf,
     309                         uint32_t offDstFrame, uint32_t cMaxDstFrames, uint32_t *pcDstFramesBlended);
     310void    AudioMixBufBlendGap(PAUDIOMIXBUF pMixBuf, PAUDIOMIXBUFWRITESTATE pState, uint32_t cFrames);
     311void    AudioMixBufCommit(PAUDIOMIXBUF pMixBuf, uint32_t cFrames);
     312
    281313void AudioMixBufClear(PAUDIOMIXBUF pMixBuf);
    282314void AudioMixBufFinish(PAUDIOMIXBUF pMixBuf, uint32_t cFramesToClear);
     
    291323uint32_t AudioMixBufUsed(PAUDIOMIXBUF pMixBuf);
    292324uint32_t AudioMixBufUsedBytes(PAUDIOMIXBUF pMixBuf);
    293 int         AudioMixBufReadAt(PAUDIOMIXBUF pMixBuf, uint32_t offFrames, void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead);
    294 int         AudioMixBufReadAtEx(PAUDIOMIXBUF pMixBuf, PCPDMAUDIOPCMPROPS pDstProps, uint32_t offFrames,
    295                                 void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead);
    296325int         AudioMixBufAcquireReadBlock(PAUDIOMIXBUF pMixBuf, void *pvBuf, uint32_t cbBuf, uint32_t *pcAcquiredFrames);
    297326int         AudioMixBufAcquireReadBlockEx(PAUDIOMIXBUF pMixBuf, PCPDMAUDIOPCMPROPS pDstProps,
  • trunk/src/VBox/Devices/Audio/AudioMixer.cpp

    r89218 r89302  
    643643
    644644                    /* Set up the mixing buffer conversion state. */
    645                     if (pSink->enmDir == PDMAUDIODIR_OUT)
     645                    if (pSink->enmDir == PDMAUDIODIR_IN)
     646                        rc = AudioMixBufInitWriteState(&pSink->MixBuf, &pMixStream->WriteState, &pStream->Props);
     647                    else
    646648                        rc = AudioMixBufInitPeekState(&pSink->MixBuf, &pMixStream->PeekState, &pStream->Props);
    647649                    if (RT_SUCCESS(rc))
     
    703705    LogFunc(("Starting '%s'. Old status: %s\n", pSink->pszName, dbgAudioMixerSinkStatusToStr(pSink->fStatus, szStatus)));
    704706
     707    AssertReturnStmt(pSink->enmDir == PDMAUDIODIR_IN || pSink->enmDir == PDMAUDIODIR_OUT,
     708                     RTCritSectLeave(&pSink->CritSect), VERR_INTERNAL_ERROR_3);
     709
    705710    /*
    706711     * Make sure the sink and its streams are all stopped.
     
    724729     * Send the command to the streams.
    725730     */
    726     if (pSink->enmDir == PDMAUDIODIR_OUT)
    727     {
    728         PAUDMIXSTREAM pStream;
    729         RTListForEach(&pSink->lstStreams, pStream, AUDMIXSTREAM, Node)
    730         {
    731             audioMixerStreamCtlInternal(pStream, PDMAUDIOSTREAMCMD_ENABLE);
    732         }
    733     }
    734     else
    735     {
    736         AssertReturnStmt(pSink->enmDir == PDMAUDIODIR_IN, RTCritSectLeave(&pSink->CritSect), VERR_INTERNAL_ERROR_3);
    737         if (pSink->In.pStreamRecSource) /* Any recording source set? */
    738         {
    739             Assert(audioMixerSinkIsStreamInList(pSink, pSink->In.pStreamRecSource));
    740             audioMixerStreamCtlInternal(pSink->In.pStreamRecSource, PDMAUDIOSTREAMCMD_ENABLE);
    741         }
     731    PAUDMIXSTREAM pStream;
     732    RTListForEach(&pSink->lstStreams, pStream, AUDMIXSTREAM, Node)
     733    {
     734        audioMixerStreamCtlInternal(pStream, PDMAUDIOSTREAMCMD_ENABLE);
    742735    }
    743736
     
    826819    LogFunc(("Draining '%s' with %#x bytes left. Old status: %s\n",
    827820             pSink->pszName, cbComming, dbgAudioMixerSinkStatusToStr(pSink->fStatus, szStatus) ));
     821
     822    AssertReturnStmt(pSink->enmDir == PDMAUDIODIR_IN || pSink->enmDir == PDMAUDIODIR_OUT,
     823                     RTCritSectLeave(&pSink->CritSect), VERR_INTERNAL_ERROR_3);
    828824
    829825    if (pSink->fStatus & AUDMIXSINK_STS_RUNNING)
     
    878874        else
    879875        {
    880             AssertReturnStmt(pSink->enmDir == PDMAUDIODIR_IN, RTCritSectLeave(&pSink->CritSect), VERR_INTERNAL_ERROR_3);
    881             if (pSink->In.pStreamRecSource) /* Any recording source set? */
     876            PAUDMIXSTREAM pStream;
     877            RTListForEach(&pSink->lstStreams, pStream, AUDMIXSTREAM, Node)
    882878            {
    883                 Assert(audioMixerSinkIsStreamInList(pSink, pSink->In.pStreamRecSource));
    884                 audioMixerStreamCtlInternal(pSink->In.pStreamRecSource, PDMAUDIOSTREAMCMD_DISABLE);
     879                audioMixerStreamCtlInternal(pStream, PDMAUDIOSTREAMCMD_DISABLE);
    885880            }
    886881            audioMixerSinkReset(pSink);
     
    10621057    if (pSink->fStatus & AUDMIXSINK_STS_RUNNING)
    10631058    {
    1064 #ifdef VBOX_AUDIO_MIXER_WITH_MIXBUF_IN
    1065 # error "Implement me!"
    1066 #else
    1067         PAUDMIXSTREAM pStreamRecSource = pSink->In.pStreamRecSource;
    1068         if (   pStreamRecSource
    1069             && (pStreamRecSource->fStatus & AUDMIXSTREAM_STATUS_CAN_READ))
    1070         {
    1071             AssertPtr(pStreamRecSource->pConn);
    1072             cbReadable = pStreamRecSource->pConn->pfnStreamGetReadable(pStreamRecSource->pConn, pStreamRecSource->pStream);
    1073         }
    1074         else if (!pStreamRecSource)
    1075             Log3Func(("[%s] No recording source specified, skipping ...\n", pSink->pszName));
    1076         else
    1077             Log3Func(("[%s] The recording source is not readable!\n", pSink->pszName));
    1078 #endif
     1059        uint32_t const cFrames = AudioMixBufLive(&pSink->MixBuf);
     1060        cbReadable = PDMAudioPropsFramesToBytes(&pSink->PCMProps, cFrames);
    10791061    }
    10801062
     
    10851067
    10861068    return cbReadable;
    1087 }
    1088 
    1089 /**
    1090  * Returns the sink's current recording source.
    1091  *
    1092  * @return  Mixer stream which currently is set as current recording source, NULL if none is set.
    1093  * @param   pSink               Audio mixer sink to return current recording source for.
    1094  */
    1095 PAUDMIXSTREAM AudioMixerSinkGetRecordingSource(PAUDMIXSINK pSink)
    1096 {
    1097     Assert(pSink->uMagic == AUDMIXSINK_MAGIC);
    1098     int rc = RTCritSectEnter(&pSink->CritSect);
    1099     AssertRCReturn(rc, NULL);
    1100 
    1101     AssertMsg(pSink->enmDir == PDMAUDIODIR_IN, ("Specified sink is not an input sink\n"));
    1102 
    1103     PAUDMIXSTREAM pStream = pSink->In.pStreamRecSource;
    1104 
    1105     int rc2 = RTCritSectLeave(&pSink->CritSect);
    1106     AssertRC(rc2);
    1107 
    1108     return pStream;
    11091069}
    11101070
     
    12201180
    12211181/**
    1222  * Reads audio data from a mixer sink.
    1223  *
    1224  * @returns VBox status code.
    1225  * @param   pSink               Mixer sink to read data from.
    1226  * @param   pvBuf               Buffer where to store the read data.
    1227  * @param   cbBuf               Buffer size (in bytes) where to store the data.
    1228  * @param   pcbRead             Number of bytes read.
    1229  */
    1230 int AudioMixerSinkRead(PAUDMIXSINK pSink, void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead)
    1231 {
    1232     AssertPtrReturn(pSink, VERR_INVALID_POINTER);
    1233     Assert(pSink->uMagic == AUDMIXSINK_MAGIC);
    1234     AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
    1235     AssertReturn(cbBuf,    VERR_INVALID_PARAMETER);
    1236     AssertPtrReturn(pcbRead, VERR_INVALID_POINTER);
    1237 
    1238     int rc = RTCritSectEnter(&pSink->CritSect);
    1239     AssertRCReturn(rc, rc);
    1240 
    1241     AssertMsg(pSink->enmDir == PDMAUDIODIR_IN,
    1242               ("Can't read from a sink which is not an input sink\n"));
    1243 
    1244     uint32_t cbRead = 0;
    1245 
    1246     /* Flag indicating whether this sink is in a 'clean' state,
    1247      * e.g. there is no more data to read from. */
    1248     bool fClean = true;
    1249 
    1250     PAUDMIXSTREAM pStreamRecSource = pSink->In.pStreamRecSource;
    1251     if (!pStreamRecSource)
    1252     {
    1253         Log3Func(("[%s] No recording source specified, skipping ...\n", pSink->pszName));
    1254     }
    1255     else if (!(pStreamRecSource->fStatus & AUDMIXSTREAM_STATUS_ENABLED)) /** @todo r=bird: AUDMIXSTREAM_STATUS_CAN_READ ?*/
    1256     {
    1257         Log3Func(("[%s] Stream '%s' disabled, skipping ...\n", pSink->pszName, pStreamRecSource->pszName));
    1258     }
    1259     else
    1260     {
    1261         uint32_t cbToRead = cbBuf;
    1262         while (cbToRead)
    1263         {
    1264             uint32_t cbReadStrm;
    1265             AssertPtr(pStreamRecSource->pConn);
    1266 #ifdef VBOX_AUDIO_MIXER_WITH_MIXBUF_IN
    1267 # error "Implement me!"
    1268 #else
    1269             rc = pStreamRecSource->pConn->pfnStreamRead(pStreamRecSource->pConn, pStreamRecSource->pStream,
    1270                                                         (uint8_t *)pvBuf + cbRead, cbToRead, &cbReadStrm);
    1271 #endif
    1272             if (RT_FAILURE(rc))
    1273                 LogFunc(("[%s] Failed reading from stream '%s': %Rrc\n", pSink->pszName, pStreamRecSource->pszName, rc));
    1274 
    1275             Log3Func(("[%s] Stream '%s': Read %RU32 bytes\n", pSink->pszName, pStreamRecSource->pszName, cbReadStrm));
    1276 
    1277             if (   RT_FAILURE(rc)
    1278                 || !cbReadStrm)
    1279                 break;
    1280 
    1281             AssertBreakStmt(cbReadStrm <= cbToRead, rc = VERR_BUFFER_OVERFLOW);
    1282             cbToRead -= cbReadStrm;
    1283             cbRead   += cbReadStrm;
    1284             Assert(cbRead <= cbBuf);
    1285         }
    1286 
    1287         uint32_t cbReadable = pStreamRecSource->pConn->pfnStreamGetReadable(pStreamRecSource->pConn, pStreamRecSource->pStream);
    1288 
    1289         /* Still some data available? Then sink is not clean (yet). */
    1290         if (cbReadable)
    1291             fClean = false;
    1292 
    1293         if (RT_SUCCESS(rc))
    1294         {
    1295             if (fClean)
    1296                 pSink->fStatus &= ~AUDMIXSINK_STS_DIRTY;
    1297 
    1298             /* Update our last read time stamp. */
    1299             pSink->tsLastReadWrittenNs = RTTimeNanoTS();
    1300 
    1301             if (pSink->pParent->fFlags & AUDMIXER_FLAGS_DEBUG)
    1302             {
    1303                 int rc2 = AudioHlpFileWrite(pSink->Dbg.pFile, pvBuf, cbRead, 0 /* fFlags */);
    1304                 AssertRC(rc2);
    1305             }
    1306         }
    1307     }
    1308     *pcbRead = cbRead;
    1309 
    1310 #ifdef LOG_ENABLED
    1311     char szStatus[AUDIOMIXERSINK_STATUS_STR_MAX];
    1312 #endif
    1313     Log2Func(("[%s] cbRead=%RU32, fClean=%RTbool, fStatus=%s, rc=%Rrc\n",
    1314               pSink->pszName, cbRead, fClean, dbgAudioMixerSinkStatusToStr(pSink->fStatus, szStatus), rc));
    1315 
    1316     RTCritSectLeave(&pSink->CritSect);
    1317     return rc;
    1318 }
    1319 
    1320 /**
    13211182 * Removes a mixer stream from a mixer sink, internal version.
    13221183 *
     
    13281189{
    13291190    AssertPtrReturn(pSink, VERR_INVALID_PARAMETER);
    1330     if (   !pStream
    1331         || !pStream->pSink) /* Not part of a sink anymore? */
    1332     {
     1191    if (pStream)
     1192    { /* likely */ }
     1193    else
    13331194        return VERR_NOT_FOUND;
    1334     }
    1335 
    13361195    AssertMsgReturn(pStream->pSink == pSink, ("Stream '%s' is not part of sink '%s'\n",
    13371196                                              pStream->pszName, pSink->pszName), VERR_NOT_FOUND);
     
    13431202    RTListNodeRemove(&pStream->Node);
    13441203
    1345     int rc = VINF_SUCCESS;
    1346 
    1347     if (pSink->enmDir == PDMAUDIODIR_IN)
    1348     {
    1349         /* Make sure to also un-set the recording source if this stream was set
    1350          * as the recording source before. */
    1351         if (pStream == pSink->In.pStreamRecSource)
    1352             rc = audioMixerSinkSetRecSourceInternal(pSink, NULL);
    1353     }
    1354 
    13551204    /* Set sink to NULL so that we know we're not part of any sink anymore. */
    13561205    pStream->pSink = NULL;
    13571206
    1358     return rc;
     1207    return VINF_SUCCESS;
    13591208}
    13601209
     
    14701319 *
    14711320 * @returns VBox status code.
    1472  * @param   pSink       The sink to set audio format for.
    1473  * @param   pPCMProps   Audio format (PCM properties) to set.
    1474  */
    1475 int AudioMixerSinkSetFormat(PAUDMIXSINK pSink, PCPDMAUDIOPCMPROPS pPCMProps)
    1476 {
    1477     AssertPtrReturn(pSink,     VERR_INVALID_POINTER);
    1478     Assert(pSink->uMagic == AUDMIXSINK_MAGIC);
    1479     AssertPtrReturn(pPCMProps, VERR_INVALID_POINTER);
    1480     AssertReturn(AudioHlpPcmPropsAreValid(pPCMProps), VERR_INVALID_PARAMETER);
     1321 * @param   pSink   The sink to set audio format for.
     1322 * @param   pProps  The properties of the new audio format.
     1323 */
     1324int AudioMixerSinkSetFormat(PAUDMIXSINK pSink, PCPDMAUDIOPCMPROPS pProps)
     1325{
     1326    AssertPtrReturn(pSink, VERR_INVALID_POINTER);
     1327    AssertReturn(pSink->uMagic == AUDMIXSINK_MAGIC, VERR_INVALID_MAGIC);
     1328    AssertPtrReturn(pProps, VERR_INVALID_POINTER);
     1329    AssertReturn(AudioHlpPcmPropsAreValid(pProps), VERR_INVALID_PARAMETER);
    14811330
    14821331    int rc = RTCritSectEnter(&pSink->CritSect);
    1483     if (RT_FAILURE(rc))
    1484         return rc;
    1485 
    1486     if (PDMAudioPropsAreEqual(&pSink->PCMProps, pPCMProps)) /* Bail out early if PCM properties are equal. */
    1487     {
    1488         rc = RTCritSectLeave(&pSink->CritSect);
    1489         AssertRC(rc);
    1490 
    1491         return rc;
    1492     }
    1493 
    1494     if (pSink->PCMProps.uHz)
    1495         LogFlowFunc(("[%s] Old format: %u bit, %RU8 channels, %RU32Hz\n", pSink->pszName,
    1496                      PDMAudioPropsSampleBits(&pSink->PCMProps), PDMAudioPropsChannels(&pSink->PCMProps), pSink->PCMProps.uHz));
    1497 
    1498     memcpy(&pSink->PCMProps, pPCMProps, sizeof(PDMAUDIOPCMPROPS));
    1499 
    1500     LogFlowFunc(("[%s] New format %u bit, %RU8 channels, %RU32Hz\n", pSink->pszName, PDMAudioPropsSampleBits(&pSink->PCMProps),
    1501                  PDMAudioPropsChannels(&pSink->PCMProps), pSink->PCMProps.uHz));
    1502 
    1503     /* Also update the sink's mixing buffer format. */
    1504     AudioMixBufDestroy(&pSink->MixBuf);
    1505     rc = AudioMixBufInit(&pSink->MixBuf, pSink->pszName, &pSink->PCMProps,
    1506                          PDMAudioPropsMilliToFrames(&pSink->PCMProps, 100 /*ms*/)); /** @todo Make this configurable? */
    1507     if (RT_SUCCESS(rc))
    1508     {
    1509         PAUDMIXSTREAM pStream;
    1510         RTListForEach(&pSink->lstStreams, pStream, AUDMIXSTREAM, Node)
    1511         {
    1512             /** @todo Invalidate mix buffers! */
    1513         }
    1514     }
    1515 
    1516     if (   RT_SUCCESS(rc)
    1517         && (pSink->pParent->fFlags & AUDMIXER_FLAGS_DEBUG))
    1518     {
    1519         AudioHlpFileClose(pSink->Dbg.pFile);
    1520 
    1521         char szName[64];
    1522         RTStrPrintf(szName, sizeof(szName), "MixerSink-%s", pSink->pszName);
    1523 
    1524         char szFile[RTPATH_MAX];
    1525         int rc2 = AudioHlpFileNameGet(szFile, RT_ELEMENTS(szFile), NULL /* Use temporary directory */, szName,
    1526                                       0 /* Instance */, AUDIOHLPFILETYPE_WAV, AUDIOHLPFILENAME_FLAGS_NONE);
    1527         if (RT_SUCCESS(rc2))
    1528         {
    1529             rc2 = AudioHlpFileCreate(AUDIOHLPFILETYPE_WAV, szFile, AUDIOHLPFILE_FLAGS_NONE, &pSink->Dbg.pFile);
    1530             if (RT_SUCCESS(rc2))
    1531                 rc2 = AudioHlpFileOpen(pSink->Dbg.pFile, AUDIOHLPFILE_DEFAULT_OPEN_FLAGS, &pSink->PCMProps);
    1532         }
    1533     }
    1534 
    1535     int rc2 = RTCritSectLeave(&pSink->CritSect);
    1536     AssertRC(rc2);
    1537 
    1538     LogFlowFuncLeaveRC(rc);
    1539     return rc;
    1540 }
    1541 
    1542 /**
    1543  * Set the current recording source of an input mixer sink, internal version.
    1544  *
    1545  * @returns VBox status code.
    1546  * @param   pSink               Input mixer sink to set recording source for.
    1547  * @param   pStream             Mixer stream to set as current recording source. Must be an input stream.
    1548  *                              Specify NULL to un-set the current recording source.
    1549  */
    1550 static int audioMixerSinkSetRecSourceInternal(PAUDMIXSINK pSink, PAUDMIXSTREAM pStream)
    1551 {
    1552     AssertMsg(pSink->enmDir == PDMAUDIODIR_IN, ("Specified sink is not an input sink\n"));
    1553 
    1554     int rc;
     1332    AssertRCReturn(rc, rc);
    15551333
    15561334    /*
    1557      * Warning: Do *not* use pfnConn->pfnEnable() for enabling/disabling streams here, as this will unconditionally (re-)enable
    1558      *          streams, which would violate / run against the (global) VM settings. See @bugref{9882}.
     1335     * Nothing to do here unless the format changed.
    15591336     */
    1560 
    1561     /* Get pointers of current recording source to make code easier to read below. */
    1562     PAUDMIXSTREAM       pCurRecSrc       = pSink->In.pStreamRecSource; /* Can be NULL. */
    1563     PPDMIAUDIOCONNECTOR pCurRecSrcConn   = NULL;
    1564     PPDMAUDIOSTREAM     pCurRecSrcStream = NULL;
    1565 
    1566     if (pCurRecSrc) /* First, disable old recording source, if any is set. */
    1567     {
    1568         pCurRecSrcConn   = pSink->In.pStreamRecSource->pConn;
    1569         AssertPtrReturn(pCurRecSrcConn, VERR_INVALID_POINTER);
    1570         pCurRecSrcStream = pCurRecSrc->pStream;
    1571         AssertPtrReturn(pCurRecSrcStream, VERR_INVALID_POINTER);
    1572 
    1573         rc = pCurRecSrcConn->pfnStreamControl(pCurRecSrcConn, pCurRecSrcStream, PDMAUDIOSTREAMCMD_DISABLE);
    1574     }
    1575     else
    1576         rc = VINF_SUCCESS;
    1577 
    1578     if (RT_SUCCESS(rc))
    1579     {
    1580         if (pStream)
    1581         {
    1582             AssertPtr(pStream->pStream);
    1583             AssertMsg(pStream->pStream->enmDir == PDMAUDIODIR_IN, ("Specified stream is not an input stream\n"));
    1584             AssertPtr(pStream->pConn);
    1585             rc = pStream->pConn->pfnStreamControl(pStream->pConn, pStream->pStream, PDMAUDIOSTREAMCMD_ENABLE);
     1337    if (!PDMAudioPropsAreEqual(&pSink->PCMProps, pProps))
     1338    {
     1339#ifdef LOG_ENABLED
     1340        char szTmp[PDMAUDIOPROPSTOSTRING_MAX];
     1341#endif
     1342        if (PDMAudioPropsHz(&pSink->PCMProps) != 0)
     1343            LogFlowFunc(("[%s] Old format: %s\n", pSink->pszName, PDMAudioPropsToString(&pSink->PCMProps, szTmp, sizeof(szTmp)) ));
     1344
     1345        pSink->PCMProps = *pProps;
     1346        LogFlowFunc(("[%s] New format: %s\n", pSink->pszName, PDMAudioPropsToString(&pSink->PCMProps, szTmp, sizeof(szTmp)) ));
     1347
     1348        /*
     1349         * Also update the sink's mixing buffer format.
     1350         */
     1351        AudioMixBufDestroy(&pSink->MixBuf);
     1352
     1353        /** @todo r=bird: Make sure we've got more room here than what's expected to
     1354         *        be moved in one guest DMA period. */
     1355        rc = AudioMixBufInit(&pSink->MixBuf, pSink->pszName, &pSink->PCMProps,
     1356                             PDMAudioPropsMilliToFrames(&pSink->PCMProps, 100 /*ms*/)); /** @todo Make this configurable? */
     1357        if (RT_SUCCESS(rc))
     1358        {
     1359            /*
     1360             * Input sinks must init their (mostly dummy) peek state.
     1361             */
     1362            if (pSink->enmDir == PDMAUDIODIR_IN)
     1363                rc = AudioMixBufInitPeekState(&pSink->MixBuf, &pSink->In.State, &pSink->PCMProps);
    15861364            if (RT_SUCCESS(rc))
    15871365            {
    1588                 pCurRecSrc = pStream;
     1366                /*
     1367                 * Re-initialize the peek/write states as the frequency, channel count
     1368                 * and other things may have changed now.
     1369                 */
     1370                PAUDMIXSTREAM pMixStream;
     1371                if (pSink->enmDir == PDMAUDIODIR_IN)
     1372                {
     1373                    RTListForEach(&pSink->lstStreams, pMixStream, AUDMIXSTREAM, Node)
     1374                    {
     1375                        int rc2 = AudioMixBufInitWriteState(&pSink->MixBuf, &pMixStream->WriteState, &pMixStream->pStream->Props);
     1376                        /** @todo remember this. */
     1377                        AssertLogRelRC(rc2);
     1378                    }
     1379                }
     1380                else
     1381                {
     1382                    RTListForEach(&pSink->lstStreams, pMixStream, AUDMIXSTREAM, Node)
     1383                    {
     1384                        int rc2 = AudioMixBufInitPeekState(&pSink->MixBuf, &pMixStream->PeekState, &pMixStream->pStream->Props);
     1385                        /** @todo remember this. */
     1386                        AssertLogRelRC(rc2);
     1387                    }
     1388                }
     1389
     1390                /*
     1391                 * Debug.
     1392                 */
     1393                if (!(pSink->pParent->fFlags & AUDMIXER_FLAGS_DEBUG))
     1394                { /* likely */ }
     1395                else
     1396                {
     1397                    AudioHlpFileClose(pSink->Dbg.pFile);
     1398
     1399                    char szName[64];
     1400                    RTStrPrintf(szName, sizeof(szName), "MixerSink-%s", pSink->pszName);
     1401                    AudioHlpFileCreateAndOpen(&pSink->Dbg.pFile, NULL /*pszDir - use temp dir*/, szName,
     1402                                              0 /*iInstance*/, &pSink->PCMProps);
     1403                }
    15891404            }
    1590             else if (pCurRecSrc) /* Stay with the current recording source (if any) and re-enable it. */
    1591             {
    1592                 rc = pCurRecSrcConn->pfnStreamControl(pCurRecSrcConn, pCurRecSrcStream, PDMAUDIOSTREAMCMD_ENABLE);
    1593             }
     1405            else
     1406                LogFunc(("AudioMixBufInitPeekState failed: %Rrc\n", rc));
    15941407        }
    15951408        else
    1596             pCurRecSrc = NULL; /* Unsetting, see audioMixerSinkRemoveStreamInternal. */
    1597     }
    1598 
    1599     /* Invalidate pointers. */
    1600     pSink->In.pStreamRecSource = pCurRecSrc;
    1601 
    1602     LogFunc(("[%s] Recording source is now '%s', rc=%Rrc\n",
    1603              pSink->pszName, pSink->In.pStreamRecSource ? pSink->In.pStreamRecSource->pszName : "<None>", rc));
    1604 
    1605     if (RT_SUCCESS(rc))
    1606         LogRel(("Audio Mixer: Setting recording source of sink '%s' to '%s'\n",
    1607                 pSink->pszName, pSink->In.pStreamRecSource ? pSink->In.pStreamRecSource->pszName : "<None>"));
    1608     else if (rc != VERR_AUDIO_STREAM_NOT_READY)
    1609         LogRel(("Audio Mixer: Setting recording source of sink '%s' to '%s' failed with %Rrc\n",
    1610                 pSink->pszName, pSink->In.pStreamRecSource ? pSink->In.pStreamRecSource->pszName : "<None>", rc));
    1611 
    1612     return rc;
    1613 }
    1614 
    1615 /**
    1616  * Set the current recording source of an input mixer sink.
    1617  *
    1618  * @returns VBox status code.
    1619  * @param   pSink               Input mixer sink to set recording source for.
    1620  * @param   pStream             Mixer stream to set as current recording source. Must be an input stream.
    1621  *                              Set to NULL to un-set the current recording source.
    1622  */
    1623 int AudioMixerSinkSetRecordingSource(PAUDMIXSINK pSink, PAUDMIXSTREAM pStream)
    1624 {
    1625     AssertPtrReturn(pSink, VERR_INVALID_POINTER);
    1626     Assert(pSink->uMagic == AUDMIXSINK_MAGIC);
    1627     if (pStream)
    1628         Assert(pStream->uMagic == AUDMIXSTREAM_MAGIC);
    1629 
    1630     int rc = RTCritSectEnter(&pSink->CritSect);
    1631     AssertRCReturn(rc, rc);
    1632 
    1633     rc = audioMixerSinkSetRecSourceInternal(pSink, pStream);
    1634 
    1635     int rc2 = RTCritSectLeave(&pSink->CritSect);
    1636     AssertRC(rc2);
    1637 
     1409            LogFunc(("AudioMixBufInit failed: %Rrc\n", rc));
     1410    }
     1411
     1412    RTCritSectLeave(&pSink->CritSect);
     1413    LogFlowFuncLeaveRC(rc);
    16381414    return rc;
    16391415}
     
    16691445}
    16701446
    1671 /**
    1672  * Updates an input mixer sink.
    1673  *
    1674  * @returns VBox status code.
    1675  * @param   pSink               Mixer sink to update.
    1676  */
    1677 static int audioMixerSinkUpdateInput(PAUDMIXSINK pSink)
    1678 {
    1679     /*
    1680      * Warning!  We currently do _not_ use the mixing buffer for input streams!
    1681      * Warning!  We currently do _not_ use the mixing buffer for input streams!
    1682      * Warning!  We currently do _not_ use the mixing buffer for input streams!
    1683      */
    1684 
    1685     /*
    1686      * Skip input sinks without a recoring source.
    1687      */
    1688     if (pSink->In.pStreamRecSource == NULL)
    1689         return VINF_SUCCESS;
    1690 
    1691     /*
    1692      * Update each mixing sink stream's status.
    1693      */
     1447
     1448/**
     1449 * Helper for audioMixerSinkUpdateInput that determins now many frames it can
     1450 * transfer from the drivers and into the sink's mixer buffer.
     1451 *
     1452 * This also updates the mixer stream status, which may involve stream re-inits.
     1453 *
     1454 * @returns Number of frames.
     1455 * @param   pSink               The sink.
     1456 * @param   pcReadableStreams   Where to return the number of readable streams.
     1457 */
     1458static uint32_t audioMixerSinkUpdateInputCalcFramesToTransfer(PAUDMIXSINK pSink, uint32_t *pcReadableStreams)
     1459{
     1460    uint32_t      cFramesToRead    = AudioMixBufFree(&pSink->MixBuf);
     1461    uint32_t      cReadableStreams = 0;
    16941462    PAUDMIXSTREAM pMixStream;
    16951463    RTListForEach(&pSink->lstStreams, pMixStream, AUDMIXSTREAM, Node)
     
    16971465        int rc2 = audioMixerStreamUpdateStatus(pMixStream);
    16981466        AssertRC(rc2);
    1699     }
     1467
     1468        if (pMixStream->fStatus & AUDMIXSTREAM_STATUS_CAN_READ)
     1469        {
     1470            PPDMIAUDIOCONNECTOR const pIConnector = pMixStream->pConn;
     1471            PPDMAUDIOSTREAM const     pStream     = pMixStream->pStream;
     1472            uint32_t                  cIgnored    = 0;
     1473            pIConnector->pfnStreamCapture(pIConnector, pStream, &cIgnored);
     1474            pIConnector->pfnStreamIterate(pIConnector, pStream);
     1475
     1476            uint32_t const cbReadable = pIConnector->pfnStreamGetReadable(pIConnector, pStream);
     1477            uint32_t cFrames = PDMAudioPropsBytesToFrames(&pStream->Props, cbReadable);
     1478            pMixStream->cFramesLastAvail = cFrames;
     1479            if (PDMAudioPropsHz(&pStream->Props) == PDMAudioPropsHz(&pSink->MixBuf.Props))
     1480            { /* likely */ }
     1481            else
     1482            {
     1483                cFrames = cFrames * PDMAudioPropsHz(&pSink->MixBuf.Props) / PDMAudioPropsHz(&pStream->Props);
     1484                cFrames = cFrames > 2 ? cFrames - 2 : 0; /* rounding safety fudge */
     1485            }
     1486            if (cFramesToRead > cFrames && !pMixStream->fUnreliable)
     1487            {
     1488                Log4Func(("%s: cFramesToRead %u -> %u; %s (%u bytes writable)\n",
     1489                          pSink->pszName, cFramesToRead, cFrames, pMixStream->pszName, cbReadable));
     1490                cFramesToRead = cFrames;
     1491            }
     1492            cReadableStreams++;
     1493        }
     1494    }
     1495
     1496    *pcReadableStreams = cReadableStreams;
     1497    return cFramesToRead;
     1498}
     1499
     1500
     1501/**
     1502 * Updates an input mixer sink.
     1503 *
     1504 * @returns VBox status code.
     1505 * @param   pSink       Mixer sink to update.
     1506 * @param   cbDmaBuf    The number of bytes in the DMA buffer.  For detecting
     1507 *                      underruns.  Zero if we don't know.
     1508 * @param   cbDmaPeriod The minimum number of bytes required for reliable DMA
     1509 *                      operation.  Zero if we don't know.
     1510 */
     1511static int audioMixerSinkUpdateInput(PAUDMIXSINK pSink, uint32_t cbDmaBuf, uint32_t cbDmaPeriod)
     1512{
     1513    PAUDMIXSTREAM pMixStream;
     1514    Assert(!(pSink->fStatus & AUDMIXSINK_STS_DRAINED_MIXBUF)); /* (can't drain input sink) */
    17001515
    17011516    /*
    1702      * Iterate and do capture on the recording source.  We ignore all other streams.
     1517     * Iterate, update status and check each mixing sink stream for how much
     1518     * we can transfer.
     1519     *
     1520     * We're currently using the minimum size of all streams, however this
     1521     * isn't a smart approach as it means one disfunctional stream can block
     1522     * working ones.  So, if we end up with zero frames and a full mixer
     1523     * buffer we'll disregard the stream that accept the smallest amount and
     1524     * try again.
    17031525     */
    1704     int rc = VINF_SUCCESS; /* not sure if error propagation is worth it... */
    1705 #if 1
    1706     pMixStream = pSink->In.pStreamRecSource;
    1707 #else
    1708     RTListForEach(&pSink->lstStreams, pMixStream, AUDMIXSTREAM, Node)
    1709 #endif
    1710     {
    1711         if (pMixStream->fStatus & AUDMIXSTREAM_STATUS_ENABLED)
    1712         {
    1713             uint32_t cFramesCaptured = 0;
    1714             int rc2 = pMixStream->pConn->pfnStreamIterate(pMixStream->pConn, pMixStream->pStream);
    1715             if (RT_SUCCESS(rc2))
     1526    uint32_t cReadableStreams  = 0;
     1527    uint32_t cFramesToXfer     = audioMixerSinkUpdateInputCalcFramesToTransfer(pSink, &cReadableStreams);
     1528    if (   cFramesToXfer != 0
     1529        || cReadableStreams <= 1
     1530        || cbDmaPeriod == 0 /* Insufficient info to decide. The update function will call us again, at least for HDA. */
     1531        || cbDmaBuf + PDMAudioPropsFramesToBytes(&pSink->PCMProps, AudioMixBufUsed(&pSink->MixBuf)) >= cbDmaPeriod)
     1532        Log3Func(("%s: cFreeFrames=%#x cFramesToXfer=%#x cReadableStreams=%#x\n", pSink->pszName,
     1533                  AudioMixBufFree(&pSink->MixBuf), cFramesToXfer, cReadableStreams));
     1534    else
     1535    {
     1536        Log3Func(("%s: MixBuf is underrunning but one or more streams only provides zero frames.  Try disregarding those...\n", pSink->pszName));
     1537        uint32_t        cReliableStreams  = 0;
     1538        uint32_t        cMarkedUnreliable = 0;
     1539        PAUDMIXSTREAM   pMixStreamMin     = NULL;
     1540        RTListForEach(&pSink->lstStreams, pMixStream, AUDMIXSTREAM, Node)
     1541        {
     1542            if (pMixStream->fStatus & AUDMIXSTREAM_STATUS_CAN_READ)
    17161543            {
    1717                 /** @todo r=bird: Check for AUDMIXSTREAM_STATUS_CAN_READ? */
    1718                 rc2 = pMixStream->pConn->pfnStreamCapture(pMixStream->pConn, pMixStream->pStream, &cFramesCaptured);
    1719                 if (RT_SUCCESS(rc2))
     1544                if (!pMixStream->fUnreliable)
    17201545                {
    1721                     if (cFramesCaptured)
    1722                         pSink->fStatus |= AUDMIXSINK_STS_DIRTY;
    1723                 }
    1724                 else
    1725                 {
    1726                     LogFunc(("%s: Failed capturing stream '%s', rc=%Rrc\n", pSink->pszName, pMixStream->pStream->szName, rc2));
    1727                     if (RT_SUCCESS(rc))
    1728                         rc = rc2;
     1546                    if (pMixStream->cFramesLastAvail == 0)
     1547                    {
     1548                        cMarkedUnreliable++;
     1549                        pMixStream->fUnreliable = true;
     1550                        Log3Func(("%s: Marked '%s' as unreliable.\n", pSink->pszName, pMixStream->pszName));
     1551                        pMixStreamMin = pMixStream;
     1552                    }
     1553                    else
     1554                    {
     1555                        if (!pMixStreamMin || pMixStream->cFramesLastAvail < pMixStreamMin->cFramesLastAvail)
     1556                            pMixStreamMin = pMixStream;
     1557                        cReliableStreams++;
     1558                    }
    17291559                }
    17301560            }
    1731             else if (RT_SUCCESS(rc))
    1732                 rc = rc2;
    1733             Log3Func(("%s: cFramesCaptured=%RU32 (rc2=%Rrc)\n", pMixStream->pStream->szName, cFramesCaptured, rc2));
    1734         }
     1561        }
     1562
     1563        if (cMarkedUnreliable == 0 && cReliableStreams > 1 && pMixStreamMin != NULL)
     1564        {
     1565            cReliableStreams--;
     1566            cMarkedUnreliable++;
     1567            pMixStreamMin->fUnreliable = true;
     1568            Log3Func(("%s: Marked '%s' as unreliable (%u frames).\n",
     1569                      pSink->pszName, pMixStreamMin->pszName, pMixStreamMin->cFramesLastAvail));
     1570        }
     1571
     1572        if (cMarkedUnreliable > 0)
     1573        {
     1574            cReadableStreams = 0;
     1575            cFramesToXfer = audioMixerSinkUpdateInputCalcFramesToTransfer(pSink, &cReadableStreams);
     1576        }
     1577
     1578        Log3Func(("%s: cFreeFrames=%#x cFramesToXfer=%#x cReadableStreams=%#x cMarkedUnreliable=%#x cReliableStreams=%#x\n",
     1579                  pSink->pszName, AudioMixBufFree(&pSink->MixBuf), cFramesToXfer,
     1580                  cReadableStreams, cMarkedUnreliable, cReliableStreams));
     1581    }
     1582
     1583    if (cReadableStreams > 0)
     1584    {
     1585        if (cFramesToXfer > 0)
     1586        {
     1587/*#define ELECTRIC_INPUT_BUFFER*/ /* if buffer code is misbehaving, enable this to catch overflows. */
     1588#ifndef ELECTRIC_INPUT_BUFFER
     1589            union
     1590            {
     1591                uint8_t  ab[8192];
     1592                uint64_t au64[8192 / sizeof(uint64_t)]; /* Use uint64_t to ensure good alignment. */
     1593            } Buf;
     1594            void * const   pvBuf = &Buf;
     1595            uint32_t const cbBuf = sizeof(Buf);
     1596#else
     1597            uint32_t const cbBuf = 0x2000 - 16;
     1598            void * const   pvBuf = RTMemEfAlloc(cbBuf, RTMEM_TAG, RT_SRC_POS);
     1599#endif
     1600
     1601            /*
     1602             * For each of the enabled streams, read cFramesToXfer frames worth
     1603             * of samples from them and merge that into the mixing buffer.
     1604             */
     1605            bool fAssign = true;
     1606            RTListForEach(&pSink->lstStreams, pMixStream, AUDMIXSTREAM, Node)
     1607            {
     1608                if (pMixStream->fStatus & AUDMIXSTREAM_STATUS_CAN_READ)
     1609                {
     1610                    PPDMIAUDIOCONNECTOR const pIConnector = pMixStream->pConn;
     1611                    PPDMAUDIOSTREAM const     pStream     = pMixStream->pStream;
     1612
     1613                    /* Calculate how many bytes we should read from this stream. */
     1614                    bool const     fResampleSrc = PDMAudioPropsHz(&pStream->Props) != PDMAudioPropsHz(&pSink->MixBuf.Props);
     1615                    uint32_t const cbSrcToXfer  = !fResampleSrc
     1616                                                ? PDMAudioPropsFramesToBytes(&pStream->Props, cFramesToXfer)
     1617                                                : PDMAudioPropsFramesToBytes(&pStream->Props, /** @todo check rounding errors here... */
     1618                                                                             cFramesToXfer * PDMAudioPropsHz(&pSink->MixBuf.Props)
     1619                                                                             / PDMAudioPropsHz(&pStream->Props));
     1620
     1621                    /* Do the reading. */
     1622                    uint32_t offSrc      = 0;
     1623                    uint32_t offDstFrame = 0;
     1624                    do
     1625                    {
     1626                        /*
     1627                         * Read a chunk from the backend.
     1628                         */
     1629                        uint32_t const cbSrcToRead = RT_MIN(cbBuf, cbSrcToXfer - offSrc);
     1630                        uint32_t       cbSrcRead   = 0;
     1631                        if (cbSrcToRead > 0)
     1632                        {
     1633                            int rc2 = pIConnector->pfnStreamRead(pIConnector, pStream, pvBuf, cbSrcToRead, &cbSrcRead);
     1634                            Log3Func(("%s: %#x L %#x => %#x bytes; rc2=%Rrc %s\n",
     1635                                      pSink->pszName, offSrc, cbSrcToRead, cbSrcRead, rc2, pMixStream->pszName));
     1636
     1637                            if (RT_SUCCESS(rc2))
     1638                                AssertLogRelMsg(cbSrcRead == cbSrcToRead || pMixStream->fUnreliable,
     1639                                                ("cbSrcRead=%#x cbSrcToRead=%#x - (sink '%s')\n",
     1640                                                 cbSrcRead, cbSrcToRead, pSink->pszName));
     1641                            else if (rc2 == VERR_AUDIO_STREAM_NOT_READY)
     1642                            {
     1643                                LogRel2(("Audio Mixer: '%s' (sink '%s'): Stream not ready - skipping.\n",
     1644                                         pMixStream->pszName, pSink->pszName)); /* must've changed status, stop processing */
     1645                                break;
     1646                            }
     1647                            else
     1648                            {
     1649                                Assert(rc2 != VERR_BUFFER_OVERFLOW);
     1650                                LogRel2(("Audio Mixer: Reading from mixer stream '%s' (sink '%s') failed, rc=%Rrc\n",
     1651                                         pMixStream->pszName, pSink->pszName, rc2));
     1652                                break;
     1653                            }
     1654                            offSrc += cbSrcRead;
     1655                        }
     1656                        else
     1657                            Assert(fResampleSrc); /** @todo test this case */
     1658
     1659                        /*
     1660                         * Assign or blend it into the mixer buffer.
     1661                         */
     1662                        uint32_t cFramesDstTransferred = 0;
     1663                        if (fAssign)
     1664                        {
     1665                            /** @todo could complicate this by detecting silence here too and stay in
     1666                             *        assign mode till we get a stream with non-silence... */
     1667                            AudioMixBufWrite(&pSink->MixBuf, &pMixStream->WriteState, pvBuf, cbSrcRead,
     1668                                             offDstFrame, cFramesToXfer - offDstFrame, &cFramesDstTransferred);
     1669                        }
     1670                        /* We don't need to blend silence buffers.  For simplicity, always blend
     1671                           when we're resampling (for rounding). */
     1672                        else if (fResampleSrc || !PDMAudioPropsIsBufferSilence(&pStream->Props, pvBuf, cbSrcRead))
     1673                        {
     1674                            AudioMixBufBlend(&pSink->MixBuf, &pMixStream->WriteState, pvBuf, cbSrcRead,
     1675                                             offDstFrame, cFramesToXfer - offDstFrame, &cFramesDstTransferred);
     1676                        }
     1677                        else
     1678                        {
     1679                            cFramesDstTransferred = PDMAudioPropsBytesToFrames(&pStream->Props, cbSrcRead);
     1680                            AudioMixBufBlendGap(&pSink->MixBuf, &pMixStream->WriteState, cFramesDstTransferred);
     1681                        }
     1682                        AssertBreak(cFramesDstTransferred > 0);
     1683
     1684                        /* Advance. */
     1685                        offDstFrame += cFramesDstTransferred;
     1686                    } while (offDstFrame < cFramesToXfer);
     1687
     1688                    /*
     1689                     * In case the first stream is misbehaving, make sure we written the entire area.
     1690                     */
     1691                    if (offDstFrame >= cFramesToXfer)
     1692                    { /* likely */ }
     1693                    else if (fAssign)
     1694                        AudioMixBufSilence(&pSink->MixBuf, &pMixStream->WriteState, offDstFrame, cFramesToXfer - offDstFrame);
     1695                    else
     1696                        AudioMixBufBlendGap(&pSink->MixBuf, &pMixStream->WriteState, cFramesToXfer - offDstFrame);
     1697                    fAssign = false;
     1698                }
     1699            }
     1700
     1701            /*
     1702             * Commit the buffer area we've written and blended into.
     1703             */
     1704            AudioMixBufCommit(&pSink->MixBuf, cFramesToXfer);
     1705
     1706#ifdef ELECTRIC_INPUT_BUFFER
     1707            RTMemEfFree(pvBuf, RT_SRC_POS);
     1708#endif
     1709        }
     1710
     1711        /*
     1712         * Set the dirty flag for what it's worth.
     1713         */
     1714        pSink->fStatus |= AUDMIXSINK_STS_DIRTY;
     1715    }
     1716    else
     1717    {
     1718        /*
     1719         * No readable stream. Clear the dirty flag if empty (pointless flag).
     1720         */
     1721        if (!AudioMixBufUsed(&pSink->MixBuf))
     1722            pSink->fStatus &= ~AUDMIXSINK_STS_DIRTY;
    17351723    }
    17361724
     
    17381726    pSink->tsLastUpdatedMs = RTTimeMilliTS();
    17391727
    1740     Assert(!(pSink->fStatus & AUDMIXSINK_STS_DRAINING));
    1741     return rc;
     1728    return VINF_SUCCESS;
    17421729}
    17431730
     
    18161803     * try again.
    18171804     */
    1818     uint32_t cReliableStreams  = 0;
    1819     uint32_t cMarkedUnreliable = 0;
    18201805    uint32_t cWritableStreams  = 0;
    18211806    uint32_t cFramesToRead     = audioMixerSinkUpdateOutputCalcFramesToRead(pSink, &cWritableStreams);
     
    18281813    {
    18291814        Log3Func(("%s: MixBuf is full but one or more streams only want zero frames.  Try disregarding those...\n", pSink->pszName));
    1830         PAUDMIXSTREAM pMixStreamMin     = NULL;
     1815        uint32_t        cReliableStreams  = 0;
     1816        uint32_t        cMarkedUnreliable = 0;
     1817        PAUDMIXSTREAM   pMixStreamMin     = NULL;
    18311818        RTListForEach(&pSink->lstStreams, pMixStream, AUDMIXSTREAM, Node)
    18321819        {
     
    20372024 *
    20382025 * @returns VBox status code.
    2039  * @param   pSink               Mixer sink to update.
    2040  */
    2041 int AudioMixerSinkUpdate(PAUDMIXSINK pSink)
     2026 * @param   pSink           Mixer sink to update.
     2027 * @param   cbDmaUsed       The DMA buffer fill for input stream, ignored for
     2028 *                          output sinks.
     2029 * @param   cbDmaPeriod     The DMA period in bytes for input stream, ignored
     2030 *                          for output sinks.
     2031 */
     2032int AudioMixerSinkUpdate(PAUDMIXSINK pSink, uint32_t cbDmaUsed, uint32_t cbDmaPeriod)
    20422033{
    20432034    AssertPtrReturn(pSink, VERR_INVALID_POINTER);
     
    20582049            rc = audioMixerSinkUpdateOutput(pSink);
    20592050        else if (pSink->enmDir == PDMAUDIODIR_IN)
    2060             rc = audioMixerSinkUpdateInput(pSink);
     2051            rc = audioMixerSinkUpdateInput(pSink, cbDmaUsed, cbDmaPeriod);
    20612052        else
    2062             AssertFailed();
     2053            AssertFailedStmt(rc = VERR_INTERNAL_ERROR_3);
    20632054    }
    20642055    else
     
    20952086             */
    20962087            if (pSink->enmDir == PDMAUDIODIR_IN)
    2097                 audioMixerSinkUpdateInput(pSink);
     2088                audioMixerSinkUpdateInput(pSink, 0 /*cbDmaUsed*/, 0 /*cbDmaPeriod*/);
    20982089
    20992090            /*
     
    24002391    const uint32_t cbCircBufWritable = (uint32_t)RTCircBufFree(pCircBuf);
    24012392    uint32_t       cbToTransfer      = RT_MIN(cbCircBufWritable, cbSinkReadable);
    2402 
    2403     /* Make sure that we always align the number of bytes when reading to the stream's PCM properties. */
    2404     cbToTransfer = PDMAudioPropsFloorBytesToFrame(&pSink->PCMProps, cbToTransfer);
    2405 
    2406     Log3Func(("idStream=%u: cbSinkReadable=%#RX32 cbCircBufWritable=%#RX32 -> cbToTransfer=%#RX32 @%#RX64\n",
    2407               idStream, cbSinkReadable, cbCircBufWritable, cbToTransfer, offStream));
     2393    uint32_t       cFramesToTransfer = PDMAudioPropsBytesToFrames(&pSink->PCMProps, cbToTransfer);
     2394    cbToTransfer = PDMAudioPropsFramesToBytes(&pSink->PCMProps, cFramesToTransfer);
     2395
     2396    Log3Func(("idStream=%u: cbSinkReadable=%#RX32 cbCircBufWritable=%#RX32 -> cbToTransfer=%#RX32 (%RU32 frames) @%#RX64\n",
     2397              idStream, cbSinkReadable, cbCircBufWritable, cbToTransfer, cFramesToTransfer, offStream));
    24082398    RT_NOREF(idStream);
    24092399
     
    24212411        uint8_t  abBuf[4096];
    24222412        uint32_t cbRead = 0;
    2423         int rc = AudioMixerSinkRead(pSink, abBuf, RT_MIN(cbToTransfer, sizeof(abBuf)), &cbRead);
    2424         AssertRCBreak(rc);
    2425         AssertMsgBreak(cbRead > 0, ("Nothing read from sink, even if %#RX32 bytes were (still) announced\n", cbToTransfer));
     2413        uint32_t cFramesRead = 0;
     2414        AudioMixBufPeek(&pSink->MixBuf, 0, cFramesToTransfer, &cFramesRead,
     2415                        &pSink->In.State, abBuf, RT_MIN(cbToTransfer, sizeof(abBuf)), &cbRead);
     2416        AssertBreak(cFramesRead > 0);
     2417        Assert(cbRead > 0);
     2418
     2419        cFramesToTransfer -= cFramesRead;
     2420        AudioMixBufAdvance(&pSink->MixBuf, cFramesRead);
    24262421
    24272422        /* Write it to the internal DMA buffer. */
     
    25922587
    25932588    uint32_t cbWritten = 0;
    2594     uint32_t cbToWrite = RT_MIN(AudioMixBufFreeBytes(&pSink->MixBuf), cbBuf);
    2595     while (cbToWrite)
     2589    uint32_t cbToWrite = AudioMixBufFreeBytes(&pSink->MixBuf);
     2590    cbToWrite = RT_MIN(cbToWrite, cbBuf);
     2591    while (cbToWrite > 0)
    25962592    {
    25972593        /* Write the data to the mixer sink's own mixing buffer.
     
    26902686                rc = AudioMixBufInitPeekState(&pSink->MixBuf, &pMixStream->PeekState, &pStream->Props);
    26912687                /** @todo we need to remember this, don't we? */
    2692                 AssertRCReturn(rc, VINF_SUCCESS);
     2688                AssertLogRelRCReturn(rc, VINF_SUCCESS);
     2689            }
     2690            else
     2691            {
     2692                rc = AudioMixBufInitWriteState(&pSink->MixBuf, &pMixStream->WriteState, &pStream->Props);
     2693                /** @todo we need to remember this, don't we? */
     2694                AssertLogRelRCReturn(rc, VINF_SUCCESS);
    26932695            }
    26942696        }
  • trunk/src/VBox/Devices/Audio/AudioMixer.h

    r89213 r89302  
    106106    /** Pointer to PDM audio stream this mixer stream handles. */
    107107    PPDMAUDIOSTREAM         pStream;
    108     /** Mixing buffer peeking state & config. */
    109     AUDIOMIXBUFPEEKSTATE    PeekState;
     108    union
     109    {
     110        /** Output: Mixing buffer peeking state & config. */
     111        AUDIOMIXBUFPEEKSTATE    PeekState;
     112        /** Input:  Mixing buffer writing state & config. */
     113        AUDIOMIXBUFWRITESTATE   WriteState;
     114    };
    110115    /** Last read (recording) / written (playback) timestamp (in ns). */
    111116    uint64_t                tsLastReadWrittenNs;
     
    196201        struct
    197202        {
    198             /** The current recording source. Can be NULL if not set. */
    199             PAUDMIXSTREAM  pStreamRecSource;
     203            /** The sink's peek state. */
     204            AUDIOMIXBUFPEEKSTATE    State;
    200205        } In;
    201         /*struct
    202         {
    203         } Out; */
    204206    };
    205207    struct
     
    300302uint32_t AudioMixerSinkGetWritable(PAUDMIXSINK pSink);
    301303PDMAUDIODIR   AudioMixerSinkGetDir(PAUDMIXSINK pSink);
    302 PAUDMIXSTREAM AudioMixerSinkGetRecordingSource(PAUDMIXSINK pSink);
    303304uint32_t AudioMixerSinkGetStatus(PAUDMIXSINK pSink);
    304305bool AudioMixerSinkIsActive(PAUDMIXSINK pSink);
    305 int AudioMixerSinkRead(PAUDMIXSINK pSink, void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead);
    306306void AudioMixerSinkRemoveStream(PAUDMIXSINK pSink, PAUDMIXSTREAM pStream);
    307307void AudioMixerSinkRemoveAllStreams(PAUDMIXSINK pSink);
    308308void AudioMixerSinkReset(PAUDMIXSINK pSink);
    309309int AudioMixerSinkSetFormat(PAUDMIXSINK pSink, PCPDMAUDIOPCMPROPS pPCMProps);
    310 int AudioMixerSinkSetRecordingSource(PAUDMIXSINK pSink, PAUDMIXSTREAM pStream);
    311310int AudioMixerSinkSetVolume(PAUDMIXSINK pSink, PPDMAUDIOVOLUME pVol);
    312311int AudioMixerSinkWrite(PAUDMIXSINK pSink, AUDMIXOP enmOp, const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten);
    313 int AudioMixerSinkUpdate(PAUDMIXSINK pSink);
     312int AudioMixerSinkUpdate(PAUDMIXSINK pSink, uint32_t cbDmaUsed, uint32_t cbDmaPeriod);
    314313
    315314int         AudioMixerSinkAddUpdateJob(PAUDMIXSINK pSink, PFNAUDMIXSINKUPDATE pfnUpdate, void *pvUser, uint32_t cMsTypicalInterval);
  • trunk/src/VBox/Devices/Audio/DevHda.cpp

    r89218 r89302  
    22112211    if (pDrv->LineIn.pMixStrm)
    22122212    {
    2213         if (AudioMixerSinkGetRecordingSource(pThisCC->SinkLineIn.pMixSink) == pDrv->LineIn.pMixStrm)
    2214             AudioMixerSinkSetRecordingSource(pThisCC->SinkLineIn.pMixSink, NULL);
    2215 
    22162213        AudioMixerSinkRemoveStream(pThisCC->SinkLineIn.pMixSink, pDrv->LineIn.pMixStrm);
    22172214        AudioMixerStreamDestroy(pDrv->LineIn.pMixStrm, pDevIns, true /*fImmediate*/);
     
    22222219    if (pDrv->MicIn.pMixStrm)
    22232220    {
    2224         if (AudioMixerSinkGetRecordingSource(pThisCC->SinkMicIn.pMixSink) == pDrv->MicIn.pMixStrm)
    2225             AudioMixerSinkSetRecordingSource(&pThisCC->SinkMicIn.pMixSink, NULL);
    2226 
    22272221        AudioMixerSinkRemoveStream(pThisCC->SinkMicIn.pMixSink, pDrv->MicIn.pMixStrm);
    22282222        AudioMixerStreamDestroy(pDrv->MicIn.pMixStrm, pDevIns, true /*fImmediate*/);
     
    23352329        rc = AudioMixerSinkAddStream(pMixSink, pMixStrm);
    23362330        LogFlowFunc(("LUN#%RU8: Added stream \"%s\" to sink, rc=%Rrc\n", pDrv->uLUN, StreamCfg.szName, rc));
    2337         if (RT_SUCCESS(rc))
    2338         {
    2339             /* If this is an input stream, always set the latest (added) stream
    2340              * as the recording source. */
    2341             /** @todo Make the recording source dynamic (CFGM?). */
    2342             if (StreamCfg.enmDir == PDMAUDIODIR_IN)
    2343             {
    2344                 PDMAUDIOBACKENDCFG Cfg;
    2345                 rc = pDrv->pConnector->pfnGetConfig(pDrv->pConnector, &Cfg);
    2346                 if (RT_SUCCESS(rc))
    2347                 {
    2348                     if (Cfg.cMaxStreamsIn) /* At least one input source available? */
    2349                     {
    2350                         rc = AudioMixerSinkSetRecordingSource(pMixSink, pMixStrm);
    2351                         LogFlowFunc(("LUN#%RU8: Recording source for '%s' -> '%s', rc=%Rrc\n",
    2352                                      pDrv->uLUN, StreamCfg.szName, Cfg.szName, rc));
    2353 
    2354                         if (RT_SUCCESS(rc))
    2355                             LogRel(("HDA: Set recording source for '%s' to '%s'\n",
    2356                                     StreamCfg.szName, Cfg.szName));
    2357                     }
    2358                     else
    2359                         LogRel(("HDA: Backend '%s' currently is not offering any recording source for '%s'\n",
    2360                                 Cfg.szName, StreamCfg.szName));
    2361                 }
    2362                 else if (RT_FAILURE(rc))
    2363                     LogFunc(("LUN#%RU8: Unable to retrieve backend configuration for '%s', rc=%Rrc\n",
    2364                              pDrv->uLUN, StreamCfg.szName, rc));
    2365             }
    2366             if (RT_FAILURE(rc))
    2367                 AudioMixerSinkRemoveStream(pMixSink, pMixStrm);
    2368         }
    23692331        if (RT_FAILURE(rc))
    23702332            AudioMixerStreamDestroy(pMixStrm, pDevIns, true /*fImmediate*/);
     
    45184480static void hdaR3DetachInternal(PPDMDEVINS pDevIns, PHDASTATER3 pThisCC, PHDADRIVER pDrv)
    45194481{
    4520     /* First, remove the driver from our list and destory it's associated streams.
    4521      * This also will un-set the driver as a recording source (if associated). */
     4482    /* Remove the driver from our list and destory it's associated streams.
     4483       This also will un-set the driver as a recording source (if associated). */
    45224484    hdaR3MixerRemoveDrv(pDevIns, pThisCC, pDrv);
    4523 
    4524     /* Next, search backwards for a capable (attached) driver which now will be the
    4525      * new recording source. */
    4526 /** @todo r=bird: This looks completely wrong.  What if the detatched devices wasn't the recording source
    4527  * and we pick a different one here?  I also don't get why we need to do this in revese order, given that
    4528  * the primary device is first.  I guess this code isn't really tested. */
    4529     PHDADRIVER pDrvCur;
    4530     RTListForEachReverse(&pThisCC->lstDrv, pDrvCur, HDADRIVER, Node)
    4531     {
    4532         if (!pDrvCur->pConnector)
    4533             continue;
    4534 
    4535         PDMAUDIOBACKENDCFG Cfg;
    4536         int rc2 = pDrvCur->pConnector->pfnGetConfig(pDrvCur->pConnector, &Cfg);
    4537         if (RT_FAILURE(rc2))
    4538             continue;
    4539 
    4540         PHDADRIVERSTREAM pDrvStrm;
    4541 # ifdef VBOX_WITH_AUDIO_HDA_MIC_IN
    4542         pDrvStrm = &pDrvCur->MicIn;
    4543         if (   pDrvStrm
    4544             && pDrvStrm->pMixStrm)
    4545         {
    4546             rc2 = AudioMixerSinkSetRecordingSource(pThisCC->SinkMicIn.pMixSink, pDrvStrm->pMixStrm);
    4547             if (RT_SUCCESS(rc2))
    4548                 LogRel2(("HDA: Set new recording source for 'Mic In' to '%s'\n", Cfg.szName));
    4549         }
    4550 # endif
    4551         pDrvStrm = &pDrvCur->LineIn;
    4552         if (   pDrvStrm
    4553             && pDrvStrm->pMixStrm)
    4554         {
    4555             rc2 = AudioMixerSinkSetRecordingSource(pThisCC->SinkLineIn.pMixSink, pDrvStrm->pMixStrm);
    4556             if (RT_SUCCESS(rc2))
    4557                 LogRel2(("HDA: Set new recording source for 'Line In' to '%s'\n", Cfg.szName));
    4558         }
    4559     }
    4560 
    45614485    LogFunc(("LUN#%u detached\n", pDrv->uLUN));
    45624486}
  • trunk/src/VBox/Devices/Audio/DevHdaStream.cpp

    r89271 r89302  
    19491949            {
    19501950                hdaR3StreamPushToMixer(pStreamShared, pStreamR3, pSink, tsNowNs);
    1951                 AudioMixerSinkUpdate(pSink);
     1951                AudioMixerSinkUpdate(pSink, 0, 0);
    19521952                AudioMixerSinkUnlock(pSink);
    19531953            }
     
    20882088            if (RT_SUCCESS(rc))
    20892089            {
    2090                 AudioMixerSinkUpdate(pSink);
     2090                AudioMixerSinkUpdate(pSink, cbStreamUsed, cbPeriod);
    20912091                hdaR3StreamPullFromMixer(pStreamR3, pSink);
    20922092                AudioMixerSinkUnlock(pSink);
  • trunk/src/VBox/Devices/Audio/DevIchAc97.cpp

    r89218 r89302  
    15111511            rc = AudioMixerSinkAddStream(pMixSink, pMixStrm);
    15121512            LogFlowFunc(("LUN#%RU8: Added stream \"%s\" to sink, rc=%Rrc\n", pDrv->uLUN, pStreamCfg->szName, rc));
    1513             if (RT_SUCCESS(rc))
    1514             {
    1515                 /* If this is an input stream, always set the latest (added) stream
    1516                  * as the recording source. */
    1517                 /** @todo Make the recording source dynamic (CFGM?). */
    1518                 if (pStreamCfg->enmDir == PDMAUDIODIR_IN)
    1519                 {
    1520                     PDMAUDIOBACKENDCFG Cfg;
    1521                     rc = pDrv->pConnector->pfnGetConfig(pDrv->pConnector, &Cfg);
    1522                     if (RT_SUCCESS(rc))
    1523                     {
    1524                         if (Cfg.cMaxStreamsIn) /* At least one input source available? */
    1525                         {
    1526                             rc = AudioMixerSinkSetRecordingSource(pMixSink, pMixStrm);
    1527                             LogFlowFunc(("LUN#%RU8: Recording source for '%s' -> '%s', rc=%Rrc\n",
    1528                                          pDrv->uLUN, pStreamCfg->szName, Cfg.szName, rc));
    1529 
    1530                             if (RT_SUCCESS(rc))
    1531                                 LogRel2(("AC97: Set recording source for '%s' to '%s'\n", pStreamCfg->szName, Cfg.szName));
    1532                         }
    1533                         else
    1534                             LogRel(("AC97: Backend '%s' currently is not offering any recording source for '%s'\n",
    1535                                     Cfg.szName, pStreamCfg->szName));
    1536                     }
    1537                     else if (RT_FAILURE(rc))
    1538                         LogFunc(("LUN#%RU8: Unable to retrieve backend configuratio for '%s', rc=%Rrc\n",
    1539                                  pDrv->uLUN, pStreamCfg->szName, rc));
    1540                 }
    1541                 if (RT_FAILURE(rc))
    1542                     AudioMixerSinkRemoveStream(pMixSink, pMixStrm);
    1543             }
    15441513            if (RT_FAILURE(rc))
    15451514                AudioMixerStreamDestroy(pMixStrm, pDevIns, true /*fImmediate*/);
     
    16401609    if (pDrv->MicIn.pMixStrm)
    16411610    {
    1642         if (AudioMixerSinkGetRecordingSource(pThisCC->pSinkMicIn) == pDrv->MicIn.pMixStrm)
    1643             AudioMixerSinkSetRecordingSource(pThisCC->pSinkMicIn, NULL);
    1644 
    16451611        AudioMixerSinkRemoveStream(pThisCC->pSinkMicIn,  pDrv->MicIn.pMixStrm);
    16461612        AudioMixerStreamDestroy(pDrv->MicIn.pMixStrm, pDevIns, true /*fImmediate*/);
     
    16501616    if (pDrv->LineIn.pMixStrm)
    16511617    {
    1652         if (AudioMixerSinkGetRecordingSource(pThisCC->pSinkLineIn) == pDrv->LineIn.pMixStrm)
    1653             AudioMixerSinkSetRecordingSource(pThisCC->pSinkLineIn, NULL);
    1654 
    16551618        AudioMixerSinkRemoveStream(pThisCC->pSinkLineIn, pDrv->LineIn.pMixStrm);
    16561619        AudioMixerStreamDestroy(pDrv->LineIn.pMixStrm, pDevIns, true /*fImmediate*/);
     
    36553618static void ichac97R3DetachInternal(PPDMDEVINS pDevIns, PAC97STATER3 pThisCC, PAC97DRIVER pDrv)
    36563619{
    3657     /* First, remove the driver from our list and destory it's associated streams.
    3658      * This also will un-set the driver as a recording source (if associated). */
     3620    /* Remove the driver from our list and destory it's associated streams.
     3621       This also will un-set the driver as a recording source (if associated). */
    36593622    ichac97R3MixerRemoveDrv(pDevIns, pThisCC, pDrv);
    3660 
    3661     /* Next, search backwards for a capable (attached) driver which now will be the
    3662      * new recording source. */
    3663 /** @todo r=bird: This looks completely wrong.  What if the detatched devices wasn't the recording source
    3664  * and we pick a different one here?  I also don't get why we need to do this in revese order, given that
    3665  * the primary device is first.  I guess this code isn't really tested. */
    3666     PAC97DRIVER pDrvCur;
    3667     RTListForEachReverse(&pThisCC->lstDrv, pDrvCur, AC97DRIVER, Node)
    3668     {
    3669         if (!pDrvCur->pConnector)
    3670             continue;
    3671 
    3672         PDMAUDIOBACKENDCFG Cfg;
    3673         int rc2 = pDrvCur->pConnector->pfnGetConfig(pDrvCur->pConnector, &Cfg);
    3674         if (RT_FAILURE(rc2))
    3675             continue;
    3676 
    3677         PAC97DRIVERSTREAM pDrvStrm = ichac97R3MixerGetDrvStream(pDrvCur, PDMAUDIODIR_IN, PDMAUDIOPATH_IN_MIC);
    3678         if (   pDrvStrm
    3679             && pDrvStrm->pMixStrm)
    3680         {
    3681             rc2 = AudioMixerSinkSetRecordingSource(pThisCC->pSinkMicIn, pDrvStrm->pMixStrm);
    3682             if (RT_SUCCESS(rc2))
    3683                 LogRel2(("AC97: Set new recording source for 'Mic In' to '%s'\n", Cfg.szName));
    3684         }
    3685 
    3686         pDrvStrm = ichac97R3MixerGetDrvStream(pDrvCur, PDMAUDIODIR_IN, PDMAUDIOPATH_IN_LINE);
    3687         if (   pDrvStrm
    3688             && pDrvStrm->pMixStrm)
    3689         {
    3690             rc2 = AudioMixerSinkSetRecordingSource(pThisCC->pSinkLineIn, pDrvStrm->pMixStrm);
    3691             if (RT_SUCCESS(rc2))
    3692                 LogRel2(("AC97: Set new recording source for 'Line In' to '%s'\n", Cfg.szName));
    3693         }
    3694     }
    3695 
    36963623    LogFunc(("Detached LUN#%u\n", pDrv->uLUN));
    36973624}
Note: See TracChangeset for help on using the changeset viewer.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette