Changeset 89302 in vbox
- Timestamp:
- May 26, 2021 9:00:51 PM (4 years ago)
- svn:sync-xref-src-repo-rev:
- 144649
- Location:
- trunk/src/VBox/Devices/Audio
- Files:
-
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Audio/AudioMixBuffer.cpp
r88889 r89302 498 498 pDst[1] = audioMixBufClipTo##a_Name(pi64Src[1]); \ 499 499 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])); \ 501 501 pDst += 2; \ 502 502 pi64Src += 2; \ … … 543 543 pi64Src += 2; /** @todo when we do multi channel mixbuf support, this can change to 1 */ \ 544 544 } \ 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 } 547 607 548 608 /* audioMixBufConvXXXS8: 8 bit, signed. */ … … 589 649 } 590 650 651 /* Encoders for peek: */ 591 652 592 653 static DECLCALLBACK(void) … … 635 696 pi64Dst += 1; 636 697 pi64Src += 2; 698 } 699 } 700 701 702 /* Decoders for write: */ 703 704 static DECLCALLBACK(void) 705 audioMixBufDecode2ChTo2ChRaw(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 711 static DECLCALLBACK(void) 712 audioMixBufDecode2ChTo1ChRaw(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 724 static DECLCALLBACK(void) 725 audioMixBufDecode1ChTo2ChRaw(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 737 static DECLCALLBACK(void) 738 audioMixBufDecode1ChTo1ChRaw(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; 637 749 } 638 750 } … … 1529 1641 1530 1642 /** 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 do1548 * 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 else1582 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 DEBUG1594 AudioMixBufDbgPrint(pMixBuf);1595 #endif1596 rc = VINF_SUCCESS;1597 }1598 else1599 {1600 AssertFailed();1601 rc = VERR_NOT_SUPPORTED;1602 }1603 }1604 else1605 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 /**1618 1643 * Reads audio frames. The audio format of the mixing buffer will be used. 1619 1644 * … … 1866 1891 1867 1892 /** 1893 * Resets the resampling state unconditionally. 1894 * 1895 * @param pRate The state to reset. 1896 */ 1897 static 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 */ 1911 DECLINLINE(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 */ 1932 DECLINLINE(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 /** 1868 1970 * Initializes the peek state, setting up encoder and (if necessary) resampling. 1869 1971 * … … 1982 2084 AssertMsgFailedReturn(("from %u to %u channels is not implemented yet\n", cSrcCh, cDstCh), VERR_OUT_OF_RANGE); 1983 2085 } 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 */ 2101 int AudioMixBufInitWriteState(PCAUDIOMIXBUF pMixBuf, PAUDIOMIXBUFWRITESTATE pState, PCPDMAUDIOPCMPROPS pProps) 2102 { 2103 AssertPtr(pMixBuf); 2104 AssertPtr(pState); 2105 AssertPtr(pProps); 1986 2106 1987 2107 /* 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. 1996 2109 */ 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 } 2005 2168 } 2006 2169 else 2007 2170 { 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) 2012 2172 { 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; 2015 2207 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); 2017 2212 } 2018 2213 } 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; 2021 2219 } 2022 2220 … … 2038 2236 uint32_t cMaxDstFrames = RT_MIN(RT_ELEMENTS(ai64DstRate) / pState->cDstChannels, cbDst / pState->cbDstFrame); 2039 2237 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); 2042 2240 *pcSrcFramesPeeked += cSrcFrames; 2043 2241 cMaxSrcFrames -= cSrcFrames; … … 2052 2250 } 2053 2251 } 2054 2055 2252 2056 2253 … … 2123 2320 2124 2321 /** 2322 * Worker for AudioMixBufPeek that handles the rate conversion case. 2323 */ 2324 DECL_NO_INLINE(static, void) 2325 AudioMixBufWriteResampling(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 */ 2376 void 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 */ 2428 void 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 */ 2451 void 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 */ 2505 void 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 /** 2125 2517 * Advances the read position of the buffer. 2126 2518 * … … 2129 2521 * @param pMixBuf The mixing buffer. 2130 2522 * @param cFrames Number of frames to advance. 2523 * @sa AudioMixBufCommit 2131 2524 */ 2132 2525 void AudioMixBufAdvance(PAUDIOMIXBUF pMixBuf, uint32_t cFrames) … … 2139 2532 pMixBuf->offRead = (pMixBuf->offRead + cFrames) % pMixBuf->cFrames; 2140 2533 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 */ 2547 void 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)); 2141 2556 } 2142 2557 -
trunk/src/VBox/Devices/Audio/AudioMixBuffer.h
r88433 r89302 159 159 /** Source (mixer) channels. */ 160 160 uint8_t cSrcChannels; 161 /** Destination (mixer)channels. */161 /** Destination channels. */ 162 162 uint8_t cDstChannels; 163 163 /** Destination frame size. */ … … 166 166 /** Pointer to peek state & config. */ 167 167 typedef AUDIOMIXBUFPEEKSTATE *PAUDIOMIXBUFPEEKSTATE; 168 169 170 /** 171 * State & config for AudioMixBufWrite, AudioMixBufSilence, AudioMixBufBlend and 172 * AudioMixBufBlendGap, created by AudioMixBufInitWriteState. 173 */ 174 typedef 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. */ 190 typedef AUDIOMIXBUFWRITESTATE *PAUDIOMIXBUFWRITESTATE; 168 191 169 192 … … 279 302 void AudioMixBufDrop(PAUDIOMIXBUF pMixBuf); 280 303 304 int AudioMixBufInitWriteState(PCAUDIOMIXBUF pMixBuf, PAUDIOMIXBUFWRITESTATE pState, PCPDMAUDIOPCMPROPS pSrcProps); 305 void AudioMixBufWrite(PAUDIOMIXBUF pMixBuf, PAUDIOMIXBUFWRITESTATE pState, const void *pvSrcBuf, uint32_t cbSrcBuf, 306 uint32_t offDstFrame, uint32_t cMaxDstFrames, uint32_t *pcDstFramesWritten); 307 void AudioMixBufSilence(PAUDIOMIXBUF pMixBuf, PAUDIOMIXBUFWRITESTATE pState, uint32_t offFrame, uint32_t cFrames); 308 void AudioMixBufBlend(PAUDIOMIXBUF pMixBuf, PAUDIOMIXBUFWRITESTATE pState, const void *pvSrcBuf, uint32_t cbSrcBuf, 309 uint32_t offDstFrame, uint32_t cMaxDstFrames, uint32_t *pcDstFramesBlended); 310 void AudioMixBufBlendGap(PAUDIOMIXBUF pMixBuf, PAUDIOMIXBUFWRITESTATE pState, uint32_t cFrames); 311 void AudioMixBufCommit(PAUDIOMIXBUF pMixBuf, uint32_t cFrames); 312 281 313 void AudioMixBufClear(PAUDIOMIXBUF pMixBuf); 282 314 void AudioMixBufFinish(PAUDIOMIXBUF pMixBuf, uint32_t cFramesToClear); … … 291 323 uint32_t AudioMixBufUsed(PAUDIOMIXBUF pMixBuf); 292 324 uint32_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);296 325 int AudioMixBufAcquireReadBlock(PAUDIOMIXBUF pMixBuf, void *pvBuf, uint32_t cbBuf, uint32_t *pcAcquiredFrames); 297 326 int AudioMixBufAcquireReadBlockEx(PAUDIOMIXBUF pMixBuf, PCPDMAUDIOPCMPROPS pDstProps, -
trunk/src/VBox/Devices/Audio/AudioMixer.cpp
r89218 r89302 643 643 644 644 /* 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 646 648 rc = AudioMixBufInitPeekState(&pSink->MixBuf, &pMixStream->PeekState, &pStream->Props); 647 649 if (RT_SUCCESS(rc)) … … 703 705 LogFunc(("Starting '%s'. Old status: %s\n", pSink->pszName, dbgAudioMixerSinkStatusToStr(pSink->fStatus, szStatus))); 704 706 707 AssertReturnStmt(pSink->enmDir == PDMAUDIODIR_IN || pSink->enmDir == PDMAUDIODIR_OUT, 708 RTCritSectLeave(&pSink->CritSect), VERR_INTERNAL_ERROR_3); 709 705 710 /* 706 711 * Make sure the sink and its streams are all stopped. … … 724 729 * Send the command to the streams. 725 730 */ 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); 742 735 } 743 736 … … 826 819 LogFunc(("Draining '%s' with %#x bytes left. Old status: %s\n", 827 820 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); 828 824 829 825 if (pSink->fStatus & AUDMIXSINK_STS_RUNNING) … … 878 874 else 879 875 { 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) 882 878 { 883 Assert(audioMixerSinkIsStreamInList(pSink, pSink->In.pStreamRecSource)); 884 audioMixerStreamCtlInternal(pSink->In.pStreamRecSource, PDMAUDIOSTREAMCMD_DISABLE); 879 audioMixerStreamCtlInternal(pStream, PDMAUDIOSTREAMCMD_DISABLE); 885 880 } 886 881 audioMixerSinkReset(pSink); … … 1062 1057 if (pSink->fStatus & AUDMIXSINK_STS_RUNNING) 1063 1058 { 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); 1079 1061 } 1080 1062 … … 1085 1067 1086 1068 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;1109 1069 } 1110 1070 … … 1220 1180 1221 1181 /** 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 else1260 {1261 uint32_t cbToRead = cbBuf;1262 while (cbToRead)1263 {1264 uint32_t cbReadStrm;1265 AssertPtr(pStreamRecSource->pConn);1266 #ifdef VBOX_AUDIO_MIXER_WITH_MIXBUF_IN1267 # error "Implement me!"1268 #else1269 rc = pStreamRecSource->pConn->pfnStreamRead(pStreamRecSource->pConn, pStreamRecSource->pStream,1270 (uint8_t *)pvBuf + cbRead, cbToRead, &cbReadStrm);1271 #endif1272 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_ENABLED1311 char szStatus[AUDIOMIXERSINK_STATUS_STR_MAX];1312 #endif1313 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 /**1321 1182 * Removes a mixer stream from a mixer sink, internal version. 1322 1183 * … … 1328 1189 { 1329 1190 AssertPtrReturn(pSink, VERR_INVALID_PARAMETER); 1330 if ( !pStream1331 || !pStream->pSink) /* Not part of a sink anymore? */1332 {1191 if (pStream) 1192 { /* likely */ } 1193 else 1333 1194 return VERR_NOT_FOUND; 1334 }1335 1336 1195 AssertMsgReturn(pStream->pSink == pSink, ("Stream '%s' is not part of sink '%s'\n", 1337 1196 pStream->pszName, pSink->pszName), VERR_NOT_FOUND); … … 1343 1202 RTListNodeRemove(&pStream->Node); 1344 1203 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 set1350 * as the recording source before. */1351 if (pStream == pSink->In.pStreamRecSource)1352 rc = audioMixerSinkSetRecSourceInternal(pSink, NULL);1353 }1354 1355 1204 /* Set sink to NULL so that we know we're not part of any sink anymore. */ 1356 1205 pStream->pSink = NULL; 1357 1206 1358 return rc;1207 return VINF_SUCCESS; 1359 1208 } 1360 1209 … … 1470 1319 * 1471 1320 * @returns VBox status code. 1472 * @param pSink 1473 * @param pP CMProps Audio format (PCM properties) to set.1474 */ 1475 int AudioMixerSinkSetFormat(PAUDMIXSINK pSink, PCPDMAUDIOPCMPROPS pP CMProps)1476 { 1477 AssertPtrReturn(pSink, 1478 Assert (pSink->uMagic == AUDMIXSINK_MAGIC);1479 AssertPtrReturn(pP CMProps, VERR_INVALID_POINTER);1480 AssertReturn(AudioHlpPcmPropsAreValid(pP CMProps), VERR_INVALID_PARAMETER);1321 * @param pSink The sink to set audio format for. 1322 * @param pProps The properties of the new audio format. 1323 */ 1324 int 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); 1481 1330 1482 1331 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); 1555 1333 1556 1334 /* 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. 1559 1336 */ 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); 1586 1364 if (RT_SUCCESS(rc)) 1587 1365 { 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 } 1589 1404 } 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)); 1594 1407 } 1595 1408 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); 1638 1414 return rc; 1639 1415 } … … 1669 1445 } 1670 1446 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 */ 1458 static uint32_t audioMixerSinkUpdateInputCalcFramesToTransfer(PAUDMIXSINK pSink, uint32_t *pcReadableStreams) 1459 { 1460 uint32_t cFramesToRead = AudioMixBufFree(&pSink->MixBuf); 1461 uint32_t cReadableStreams = 0; 1694 1462 PAUDMIXSTREAM pMixStream; 1695 1463 RTListForEach(&pSink->lstStreams, pMixStream, AUDMIXSTREAM, Node) … … 1697 1465 int rc2 = audioMixerStreamUpdateStatus(pMixStream); 1698 1466 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 */ 1511 static 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) */ 1700 1515 1701 1516 /* 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. 1703 1525 */ 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) 1716 1543 { 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) 1720 1545 { 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 } 1729 1559 } 1730 1560 } 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; 1735 1723 } 1736 1724 … … 1738 1726 pSink->tsLastUpdatedMs = RTTimeMilliTS(); 1739 1727 1740 Assert(!(pSink->fStatus & AUDMIXSINK_STS_DRAINING)); 1741 return rc; 1728 return VINF_SUCCESS; 1742 1729 } 1743 1730 … … 1816 1803 * try again. 1817 1804 */ 1818 uint32_t cReliableStreams = 0;1819 uint32_t cMarkedUnreliable = 0;1820 1805 uint32_t cWritableStreams = 0; 1821 1806 uint32_t cFramesToRead = audioMixerSinkUpdateOutputCalcFramesToRead(pSink, &cWritableStreams); … … 1828 1813 { 1829 1814 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; 1831 1818 RTListForEach(&pSink->lstStreams, pMixStream, AUDMIXSTREAM, Node) 1832 1819 { … … 2037 2024 * 2038 2025 * @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 */ 2032 int AudioMixerSinkUpdate(PAUDMIXSINK pSink, uint32_t cbDmaUsed, uint32_t cbDmaPeriod) 2042 2033 { 2043 2034 AssertPtrReturn(pSink, VERR_INVALID_POINTER); … … 2058 2049 rc = audioMixerSinkUpdateOutput(pSink); 2059 2050 else if (pSink->enmDir == PDMAUDIODIR_IN) 2060 rc = audioMixerSinkUpdateInput(pSink );2051 rc = audioMixerSinkUpdateInput(pSink, cbDmaUsed, cbDmaPeriod); 2061 2052 else 2062 AssertFailed ();2053 AssertFailedStmt(rc = VERR_INTERNAL_ERROR_3); 2063 2054 } 2064 2055 else … … 2095 2086 */ 2096 2087 if (pSink->enmDir == PDMAUDIODIR_IN) 2097 audioMixerSinkUpdateInput(pSink );2088 audioMixerSinkUpdateInput(pSink, 0 /*cbDmaUsed*/, 0 /*cbDmaPeriod*/); 2098 2089 2099 2090 /* … … 2400 2391 const uint32_t cbCircBufWritable = (uint32_t)RTCircBufFree(pCircBuf); 2401 2392 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)); 2408 2398 RT_NOREF(idStream); 2409 2399 … … 2421 2411 uint8_t abBuf[4096]; 2422 2412 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); 2426 2421 2427 2422 /* Write it to the internal DMA buffer. */ … … 2592 2587 2593 2588 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) 2596 2592 { 2597 2593 /* Write the data to the mixer sink's own mixing buffer. … … 2690 2686 rc = AudioMixBufInitPeekState(&pSink->MixBuf, &pMixStream->PeekState, &pStream->Props); 2691 2687 /** @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); 2693 2695 } 2694 2696 } -
trunk/src/VBox/Devices/Audio/AudioMixer.h
r89213 r89302 106 106 /** Pointer to PDM audio stream this mixer stream handles. */ 107 107 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 }; 110 115 /** Last read (recording) / written (playback) timestamp (in ns). */ 111 116 uint64_t tsLastReadWrittenNs; … … 196 201 struct 197 202 { 198 /** The current recording source. Can be NULL if not set. */199 PAUDMIXSTREAM pStreamRecSource;203 /** The sink's peek state. */ 204 AUDIOMIXBUFPEEKSTATE State; 200 205 } In; 201 /*struct202 {203 } Out; */204 206 }; 205 207 struct … … 300 302 uint32_t AudioMixerSinkGetWritable(PAUDMIXSINK pSink); 301 303 PDMAUDIODIR AudioMixerSinkGetDir(PAUDMIXSINK pSink); 302 PAUDMIXSTREAM AudioMixerSinkGetRecordingSource(PAUDMIXSINK pSink);303 304 uint32_t AudioMixerSinkGetStatus(PAUDMIXSINK pSink); 304 305 bool AudioMixerSinkIsActive(PAUDMIXSINK pSink); 305 int AudioMixerSinkRead(PAUDMIXSINK pSink, void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead);306 306 void AudioMixerSinkRemoveStream(PAUDMIXSINK pSink, PAUDMIXSTREAM pStream); 307 307 void AudioMixerSinkRemoveAllStreams(PAUDMIXSINK pSink); 308 308 void AudioMixerSinkReset(PAUDMIXSINK pSink); 309 309 int AudioMixerSinkSetFormat(PAUDMIXSINK pSink, PCPDMAUDIOPCMPROPS pPCMProps); 310 int AudioMixerSinkSetRecordingSource(PAUDMIXSINK pSink, PAUDMIXSTREAM pStream);311 310 int AudioMixerSinkSetVolume(PAUDMIXSINK pSink, PPDMAUDIOVOLUME pVol); 312 311 int AudioMixerSinkWrite(PAUDMIXSINK pSink, AUDMIXOP enmOp, const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten); 313 int AudioMixerSinkUpdate(PAUDMIXSINK pSink );312 int AudioMixerSinkUpdate(PAUDMIXSINK pSink, uint32_t cbDmaUsed, uint32_t cbDmaPeriod); 314 313 315 314 int AudioMixerSinkAddUpdateJob(PAUDMIXSINK pSink, PFNAUDMIXSINKUPDATE pfnUpdate, void *pvUser, uint32_t cMsTypicalInterval); -
trunk/src/VBox/Devices/Audio/DevHda.cpp
r89218 r89302 2211 2211 if (pDrv->LineIn.pMixStrm) 2212 2212 { 2213 if (AudioMixerSinkGetRecordingSource(pThisCC->SinkLineIn.pMixSink) == pDrv->LineIn.pMixStrm)2214 AudioMixerSinkSetRecordingSource(pThisCC->SinkLineIn.pMixSink, NULL);2215 2216 2213 AudioMixerSinkRemoveStream(pThisCC->SinkLineIn.pMixSink, pDrv->LineIn.pMixStrm); 2217 2214 AudioMixerStreamDestroy(pDrv->LineIn.pMixStrm, pDevIns, true /*fImmediate*/); … … 2222 2219 if (pDrv->MicIn.pMixStrm) 2223 2220 { 2224 if (AudioMixerSinkGetRecordingSource(pThisCC->SinkMicIn.pMixSink) == pDrv->MicIn.pMixStrm)2225 AudioMixerSinkSetRecordingSource(&pThisCC->SinkMicIn.pMixSink, NULL);2226 2227 2221 AudioMixerSinkRemoveStream(pThisCC->SinkMicIn.pMixSink, pDrv->MicIn.pMixStrm); 2228 2222 AudioMixerStreamDestroy(pDrv->MicIn.pMixStrm, pDevIns, true /*fImmediate*/); … … 2335 2329 rc = AudioMixerSinkAddStream(pMixSink, pMixStrm); 2336 2330 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) stream2340 * 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 else2359 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 }2369 2331 if (RT_FAILURE(rc)) 2370 2332 AudioMixerStreamDestroy(pMixStrm, pDevIns, true /*fImmediate*/); … … 4518 4480 static void hdaR3DetachInternal(PPDMDEVINS pDevIns, PHDASTATER3 pThisCC, PHDADRIVER pDrv) 4519 4481 { 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). */ 4522 4484 hdaR3MixerRemoveDrv(pDevIns, pThisCC, pDrv); 4523 4524 /* Next, search backwards for a capable (attached) driver which now will be the4525 * new recording source. */4526 /** @todo r=bird: This looks completely wrong. What if the detatched devices wasn't the recording source4527 * and we pick a different one here? I also don't get why we need to do this in revese order, given that4528 * 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_IN4542 pDrvStrm = &pDrvCur->MicIn;4543 if ( pDrvStrm4544 && 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 # endif4551 pDrvStrm = &pDrvCur->LineIn;4552 if ( pDrvStrm4553 && 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 4561 4485 LogFunc(("LUN#%u detached\n", pDrv->uLUN)); 4562 4486 } -
trunk/src/VBox/Devices/Audio/DevHdaStream.cpp
r89271 r89302 1949 1949 { 1950 1950 hdaR3StreamPushToMixer(pStreamShared, pStreamR3, pSink, tsNowNs); 1951 AudioMixerSinkUpdate(pSink );1951 AudioMixerSinkUpdate(pSink, 0, 0); 1952 1952 AudioMixerSinkUnlock(pSink); 1953 1953 } … … 2088 2088 if (RT_SUCCESS(rc)) 2089 2089 { 2090 AudioMixerSinkUpdate(pSink );2090 AudioMixerSinkUpdate(pSink, cbStreamUsed, cbPeriod); 2091 2091 hdaR3StreamPullFromMixer(pStreamR3, pSink); 2092 2092 AudioMixerSinkUnlock(pSink); -
trunk/src/VBox/Devices/Audio/DevIchAc97.cpp
r89218 r89302 1511 1511 rc = AudioMixerSinkAddStream(pMixSink, pMixStrm); 1512 1512 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) stream1516 * 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 else1534 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 }1544 1513 if (RT_FAILURE(rc)) 1545 1514 AudioMixerStreamDestroy(pMixStrm, pDevIns, true /*fImmediate*/); … … 1640 1609 if (pDrv->MicIn.pMixStrm) 1641 1610 { 1642 if (AudioMixerSinkGetRecordingSource(pThisCC->pSinkMicIn) == pDrv->MicIn.pMixStrm)1643 AudioMixerSinkSetRecordingSource(pThisCC->pSinkMicIn, NULL);1644 1645 1611 AudioMixerSinkRemoveStream(pThisCC->pSinkMicIn, pDrv->MicIn.pMixStrm); 1646 1612 AudioMixerStreamDestroy(pDrv->MicIn.pMixStrm, pDevIns, true /*fImmediate*/); … … 1650 1616 if (pDrv->LineIn.pMixStrm) 1651 1617 { 1652 if (AudioMixerSinkGetRecordingSource(pThisCC->pSinkLineIn) == pDrv->LineIn.pMixStrm)1653 AudioMixerSinkSetRecordingSource(pThisCC->pSinkLineIn, NULL);1654 1655 1618 AudioMixerSinkRemoveStream(pThisCC->pSinkLineIn, pDrv->LineIn.pMixStrm); 1656 1619 AudioMixerStreamDestroy(pDrv->LineIn.pMixStrm, pDevIns, true /*fImmediate*/); … … 3655 3618 static void ichac97R3DetachInternal(PPDMDEVINS pDevIns, PAC97STATER3 pThisCC, PAC97DRIVER pDrv) 3656 3619 { 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). */ 3659 3622 ichac97R3MixerRemoveDrv(pDevIns, pThisCC, pDrv); 3660 3661 /* Next, search backwards for a capable (attached) driver which now will be the3662 * new recording source. */3663 /** @todo r=bird: This looks completely wrong. What if the detatched devices wasn't the recording source3664 * and we pick a different one here? I also don't get why we need to do this in revese order, given that3665 * 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 ( pDrvStrm3679 && 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 ( pDrvStrm3688 && 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 3696 3623 LogFunc(("Detached LUN#%u\n", pDrv->uLUN)); 3697 3624 }
Note:
See TracChangeset
for help on using the changeset viewer.