Changeset 73809 in vbox for trunk/src/VBox/Devices/Audio
- Timestamp:
- Aug 22, 2018 8:27:04 AM (6 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Audio/AudioMixer.cpp
r73794 r73809 72 72 static int audioMixerSinkSetRecSourceInternal(PAUDMIXSINK pSink, PAUDMIXSTREAM pStream); 73 73 static int audioMixerSinkUpdateInternal(PAUDMIXSINK pSink); 74 static int audioMixerSinkMultiplexSync(PAUDMIXSINK pSink, AUDMIXOP enmOp, const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWrittenMin); 75 static int audioMixerSinkWriteToStream(PAUDMIXSINK pSink, PAUDMIXSTREAM pMixStream); 76 static int audioMixerSinkWriteToStreamEx(PAUDMIXSINK pSink, PAUDMIXSTREAM pMixStream, uint32_t cbToWrite, uint32_t *pcbWritten); 74 77 75 78 int audioMixerStreamCtlInternal(PAUDMIXSTREAM pMixStream, PDMAUDIOSTREAMCMD enmCmd, uint32_t fCtl); … … 1565 1568 /* Number of disabled streams of this sink. */ 1566 1569 uint8_t cStreamsDisabled = pSink->cStreams; 1570 1571 /* Next, try to write (multiplex) as much audio data as possible to all connected mixer streams. */ 1572 uint32_t cbToWriteToStreams = AudioMixBufUsedBytes(&pSink->MixBuf); 1573 1574 uint8_t arrChunkBuf[_1K]; /** @todo Hm ... some zero copy / shared buffers would be nice! */ 1575 while (cbToWriteToStreams) 1576 { 1577 uint32_t cfChunk; 1578 rc = AudioMixBufAcquireReadBlock(&pSink->MixBuf, arrChunkBuf, RT_MIN(cbToWriteToStreams, sizeof(arrChunkBuf)), &cfChunk); 1579 if (RT_FAILURE(rc)) 1580 break; 1581 1582 const uint32_t cbChunk = DrvAudioHlpFramesToBytes(cfChunk, &pSink->PCMProps); 1583 Assert(cbChunk <= sizeof(arrChunkBuf)); 1584 1585 /* Multiplex the current chunk in a synchronized fashion to all connected streams. */ 1586 uint32_t cbChunkWrittenMin = 0; 1587 rc = audioMixerSinkMultiplexSync(pSink, AUDMIXOP_COPY, arrChunkBuf, cbChunk, &cbChunkWrittenMin); 1588 if (RT_SUCCESS(rc)) 1589 { 1590 PAUDMIXSTREAM pMixStream; 1591 RTListForEach(&pSink->lstStreams, pMixStream, AUDMIXSTREAM, Node) 1592 { 1593 int rc2 = audioMixerSinkWriteToStream(pSink, pMixStream); 1594 AssertRC(rc2); 1595 } 1596 } 1597 1598 Log3Func(("[%s] cbChunk=%RU32, cbChunkWrittenMin=%RU32\n", pSink->pszName, cbChunk, cbChunkWrittenMin)); 1599 1600 AudioMixBufReleaseReadBlock(&pSink->MixBuf, AUDIOMIXBUF_B2F(&pSink->MixBuf, cbChunkWrittenMin)); 1601 1602 if ( RT_FAILURE(rc) 1603 || cbChunkWrittenMin == 0) 1604 break; 1605 1606 Assert(cbToWriteToStreams >= cbChunkWrittenMin); 1607 cbToWriteToStreams -= cbChunkWrittenMin; 1608 } 1609 1610 if ( !(pSink->fStatus & AUDMIXSINK_STS_DIRTY) 1611 && AudioMixBufUsed(&pSink->MixBuf)) /* Still audio output data left? Consider the sink as being "dirty" then. */ 1612 { 1613 /* Set dirty bit. */ 1614 pSink->fStatus |= AUDMIXSINK_STS_DIRTY; 1615 } 1567 1616 1568 1617 PAUDMIXSTREAM pMixStream, pMixStreamNext; … … 1709 1758 1710 1759 /** 1711 * Writes audio output data to all connected mixer streams (multiplex). 1760 * Writes (buffered) output data of a sink's stream to the bound audio connector stream. 1761 * 1762 * @returns IPRT status code. 1763 * @param pSink Sink of stream that contains the mixer stream. 1764 * @param pMixStream Mixer stream to write output data for. 1765 */ 1766 static int audioMixerSinkWriteToStream(PAUDMIXSINK pSink, PAUDMIXSTREAM pMixStream) 1767 { 1768 if (!pMixStream->pCircBuf) 1769 return VINF_SUCCESS; 1770 1771 return audioMixerSinkWriteToStreamEx(pSink, pMixStream, RTCircBufUsed(pMixStream->pCircBuf), NULL /* pcbWritten */); 1772 } 1773 1774 /** 1775 * Writes (buffered) output data of a sink's stream to the bound audio connector stream, extended version. 1776 * 1777 * @returns IPRT status code. 1778 * @param pSink Sink of stream that contains the mixer stream. 1779 * @param pMixStream Mixer stream to write output data for. 1780 * @param cbToWrite Size (in bytes) to write. 1781 * @param pcbWritten Size (in bytes) written on success. Optional. 1782 */ 1783 static int audioMixerSinkWriteToStreamEx(PAUDMIXSINK pSink, PAUDMIXSTREAM pMixStream, uint32_t cbToWrite, uint32_t *pcbWritten) 1784 { 1785 /* pcbWritten is optional. */ 1786 1787 if ( !cbToWrite 1788 || !DrvAudioHlpStreamStatusCanWrite(pMixStream->pConn->pfnStreamGetStatus(pMixStream->pConn, pMixStream->pStream))) 1789 { 1790 if (pcbWritten) 1791 *pcbWritten = 0; 1792 1793 return VINF_SUCCESS; 1794 } 1795 1796 PRTCIRCBUF pCircBuf = pMixStream->pCircBuf; 1797 1798 const uint32_t cbWritableStream = pMixStream->pConn->pfnStreamGetWritable(pMixStream->pConn, pMixStream->pStream); 1799 cbToWrite = RT_MIN(cbToWrite, RT_MIN((uint32_t)RTCircBufUsed(pCircBuf), cbWritableStream)); 1800 1801 Log3Func(("[%s] cbWritableStream=%RU32, cbToWrite=%RU32\n", 1802 pMixStream->pszName, cbWritableStream, cbToWrite)); 1803 1804 uint32_t cbWritten = 0; 1805 1806 int rc = VINF_SUCCESS; 1807 1808 while (cbToWrite) 1809 { 1810 void *pvChunk; 1811 size_t cbChunk; 1812 RTCircBufAcquireReadBlock(pCircBuf, cbToWrite, &pvChunk, &cbChunk); 1813 1814 Log3Func(("[%s] cbChunk=%RU32\n", pMixStream->pszName, cbChunk)); 1815 1816 uint32_t cbChunkWritten = 0; 1817 if (cbChunk) 1818 { 1819 rc = pMixStream->pConn->pfnStreamWrite(pMixStream->pConn, pMixStream->pStream, pvChunk, (uint32_t)cbChunk, 1820 &cbChunkWritten); 1821 if (RT_FAILURE(rc)) 1822 { 1823 if (rc == VERR_BUFFER_OVERFLOW) 1824 { 1825 LogRel2(("Mixer: Buffer overrun for mixer stream '%s' (sink '%s')\n", pMixStream->pszName, pSink->pszName)); 1826 break; 1827 } 1828 else if (rc != VERR_AUDIO_STREAM_NOT_READY) 1829 LogRel2(("Mixer: Writing to mixer stream '%s' (sink '%s') failed, rc=%Rrc\n", 1830 pMixStream->pszName, pSink->pszName, rc)); 1831 1832 LogFunc(("[%s] Failed writing to stream '%s': %Rrc\n", pSink->pszName, pMixStream->pszName, rc)); 1833 } 1834 } 1835 1836 RTCircBufReleaseReadBlock(pCircBuf, cbChunkWritten); 1837 1838 if ( RT_FAILURE(rc) 1839 || !cbChunkWritten) 1840 break; 1841 1842 Assert(cbToWrite >= cbChunkWritten); 1843 cbToWrite -= (uint32_t)cbChunkWritten; 1844 1845 cbWritten += (uint32_t)cbChunkWritten; 1846 } 1847 1848 Log3Func(("[%s] cbWritten=%RU32\n", pMixStream->pszName, cbWritten)); 1849 1850 if (pcbWritten) 1851 *pcbWritten = cbWritten; 1852 1853 #ifdef DEBUG_andy 1854 AssertRC(rc); 1855 #endif 1856 1857 return rc; 1858 } 1859 1860 /** 1861 * Multiplexes audio output data to all connected mixer streams in a synchronized fashion, e.g. 1862 * only multiplex as much data as all streams can handle at this time. 1712 1863 * 1713 1864 * @returns IPRT status code. … … 1716 1867 * @param pvBuf Pointer to audio data to write. 1717 1868 * @param cbBuf Size (in bytes) of audio data to write. 1718 * @param pcbWrittenMin Returns minimum size (in bytes) successfully written by all mixer streams. Optional. 1719 */ 1720 int audioMixerSinkWriteToStreams(PAUDMIXSINK pSink, AUDMIXOP enmOp, const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWrittenMin) 1721 { 1869 * @param pcbWrittenMin Returns minimum size (in bytes) successfully written to all mixer streams. Optional. 1870 */ 1871 static int audioMixerSinkMultiplexSync(PAUDMIXSINK pSink, AUDMIXOP enmOp, const void *pvBuf, uint32_t cbBuf, 1872 uint32_t *pcbWrittenMin) 1873 { 1874 AssertReturn(cbBuf, VERR_INVALID_PARAMETER); 1722 1875 RT_NOREF(enmOp); 1723 1876 1877 AssertMsg(pSink->enmDir == AUDMIXSINKDIR_OUTPUT, 1878 ("%s: Can't multiplex to a sink which is not an output sink\n", pSink->pszName)); 1879 1724 1880 int rc = VINF_SUCCESS; 1725 1881 1726 uint32_t cbWrittenMin = UINT32_MAX; 1882 uint32_t cbToWriteMin = UINT32_MAX; 1883 1884 Log3Func(("[%s] cbBuf=%RU32\n", pSink->pszName, cbBuf)); 1727 1885 1728 1886 PAUDMIXSTREAM pMixStream; … … 1732 1890 continue; 1733 1891 1734 PRTCIRCBUF pCircBuf = pMixStream->pCircBuf; 1735 void *pvChunk; 1736 size_t cbChunk; 1737 1738 uint32_t cbWrittenBuf = 0; 1739 uint32_t cbToWriteBuf = RT_MIN(cbBuf, (uint32_t)RTCircBufFree(pCircBuf)); 1740 while (cbToWriteBuf) 1741 { 1742 RTCircBufAcquireWriteBlock(pCircBuf, cbToWriteBuf, &pvChunk, &cbChunk); 1743 1744 if (cbChunk) 1745 memcpy(pvChunk, (uint8_t *)pvBuf + cbWrittenBuf, cbChunk); 1746 1747 RTCircBufReleaseWriteBlock(pCircBuf, cbChunk); 1748 1749 cbWrittenBuf += (uint32_t)cbChunk; 1750 Assert(cbWrittenBuf <= cbBuf); 1751 1752 Assert(cbToWriteBuf >= cbChunk); 1753 cbToWriteBuf -= (uint32_t)cbChunk; 1754 } 1755 1756 cbWrittenMin = RT_MIN(cbWrittenMin, cbWrittenBuf); 1757 1758 if (cbWrittenBuf) /* Update the mixer stream's last written time stamp. */ 1759 pMixStream->tsLastReadWrittenNs = RTTimeNanoTS(); 1760 1761 uint32_t cbToWriteStream = DrvAudioHlpBytesAlign(cbWrittenBuf, &pSink->PCMProps); 1762 uint32_t cbWrittenStream = 0; 1763 1764 int rc2 = VINF_SUCCESS; 1765 1766 while (cbToWriteStream) 1767 { 1768 RTCircBufAcquireReadBlock(pCircBuf, cbToWriteStream, &pvChunk, &cbChunk); 1769 1770 uint32_t cbChunkWritten = 0; 1771 if (cbChunk) 1892 cbToWriteMin = RT_MIN(cbBuf, RT_MIN(cbToWriteMin, RTCircBufFree(pMixStream->pCircBuf))); 1893 } 1894 1895 if (cbToWriteMin == UINT32_MAX) /* No space at all? */ 1896 cbToWriteMin = 0; 1897 1898 if (cbToWriteMin) 1899 { 1900 RTListForEach(&pSink->lstStreams, pMixStream, AUDMIXSTREAM, Node) 1901 { 1902 PRTCIRCBUF pCircBuf = pMixStream->pCircBuf; 1903 void *pvChunk; 1904 size_t cbChunk; 1905 1906 uint32_t cbWrittenBuf = 0; 1907 uint32_t cbToWriteBuf = cbToWriteMin; 1908 1909 while (cbToWriteBuf) 1772 1910 { 1773 rc2 = pMixStream->pConn->pfnStreamWrite(pMixStream->pConn, pMixStream->pStream, pvChunk, (uint32_t)cbChunk, 1774 &cbChunkWritten); 1775 if (RT_FAILURE(rc2)) 1776 { 1777 if (rc2 == VERR_BUFFER_OVERFLOW) 1778 { 1779 LogRel2(("Mixer: Buffer overrun for mixer stream '%s' (sink '%s')\n", pMixStream->pszName, pSink->pszName)); 1780 #ifdef DEBUG_andy 1781 AssertRC(rc2); 1782 #endif 1783 } 1784 else if (rc2 != VERR_AUDIO_STREAM_NOT_READY) 1785 LogRel2(("Mixer: Writing to mixer stream '%s' (sink '%s') failed, rc=%Rrc\n", pMixStream->pszName, pSink->pszName, rc2)); 1786 1787 LogFunc(("[%s] Failed writing to stream '%s': %Rrc\n", pSink->pszName, pMixStream->pszName, rc2)); 1788 } 1911 RTCircBufAcquireWriteBlock(pCircBuf, cbToWriteBuf, &pvChunk, &cbChunk); 1912 1913 if (cbChunk) 1914 memcpy(pvChunk, (uint8_t *)pvBuf + cbWrittenBuf, cbChunk); 1915 1916 RTCircBufReleaseWriteBlock(pCircBuf, cbChunk); 1917 1918 cbWrittenBuf += (uint32_t)cbChunk; 1919 Assert(cbWrittenBuf <= cbBuf); 1920 1921 Assert(cbToWriteBuf >= cbChunk); 1922 cbToWriteBuf -= (uint32_t)cbChunk; 1789 1923 } 1790 1924 1791 RTCircBufReleaseReadBlock(pCircBuf, cbChunkWritten); 1792 1793 if (RT_FAILURE(rc2)) 1794 break; 1795 1796 Assert(cbToWriteStream >= cbChunk); 1797 cbToWriteStream -= (uint32_t)cbChunk; 1798 1799 cbWrittenStream += (uint32_t)cbChunk; 1800 Assert(cbWrittenStream <= cbBuf); 1801 } 1802 1803 Log3Func(("[%s] cbBuf=%RU32, cbWrittenBuf=%RU32, cbWrittenStream=%RU32\n", 1804 pMixStream->pszName, cbBuf, cbWrittenBuf, cbWrittenStream)); 1805 } 1806 1807 if (cbWrittenMin == UINT32_MAX) /* Nothing written? */ 1808 cbWrittenMin = 0; 1925 if (cbWrittenBuf) /* Update the mixer stream's last written time stamp. */ 1926 pMixStream->tsLastReadWrittenNs = RTTimeNanoTS(); 1927 } 1928 } 1929 1930 Log3Func(("[%s] cbBuf=%RU32, cbToWriteMin=%RU32\n", pSink->pszName, cbBuf, cbToWriteMin)); 1809 1931 1810 1932 if (pcbWrittenMin) 1811 *pcbWrittenMin = cb WrittenMin;1933 *pcbWrittenMin = cbToWriteMin; 1812 1934 1813 1935 return rc; … … 1841 1963 ("%s: Can't write to a sink which is not an output sink\n", pSink->pszName)); 1842 1964 1843 #ifdef VBOX_AUDIO_MIXER_WITH_MIXBUF 1965 Assert(cbBuf <= AudioMixBufFreeBytes(&pSink->MixBuf)); 1966 1844 1967 uint32_t cbWritten = 0; 1845 1968 uint32_t cbToWrite = cbBuf; … … 1860 1983 } 1861 1984 1862 Assert(cbWritten <= cbBuf); 1863 1864 if ( RT_FAILURE(rc) 1865 || cbWritten < cbBuf) 1866 { 1867 LogRel2(("Mixer: Buffer overrun for mixer sink '%s' (only %RU32/%RU32 bytes written)\n", 1868 pSink->pszName, cbWritten, cbBuf)); 1869 # ifdef DEBUG_andy 1870 AssertFailed(); 1871 # endif 1872 } 1873 1874 /* Next, try to write (multiplex) as much audio data as possible to all connected mixer streams. */ 1875 uint8_t arrChunkBuf[_1K]; /** @todo Hm ... some zero copy / shared buffers would be nice! */ 1876 while (cbWritten) 1877 { 1878 uint32_t cfChunk; 1879 rc = AudioMixBufAcquireReadBlock(&pSink->MixBuf, arrChunkBuf, sizeof(arrChunkBuf), &cfChunk); 1880 if (RT_FAILURE(rc)) 1881 break; 1882 1883 const uint32_t cbChunk = DrvAudioHlpFramesToBytes(cfChunk, &pSink->PCMProps); 1884 Assert(cbChunk <= sizeof(arrChunkBuf)); 1885 rc = audioMixerSinkWriteToStreams(pSink, enmOp, arrChunkBuf, cbChunk, NULL /* pcbWrittenMin */); 1886 AudioMixBufReleaseReadBlock(&pSink->MixBuf, cfChunk); 1887 1888 Assert(cbWritten >= cbChunk); 1889 cbWritten -= cbChunk; 1890 } 1891 1892 if ( !(pSink->fStatus & AUDMIXSINK_STS_DIRTY) 1893 && AudioMixBufUsed(&pSink->MixBuf)) /* Still audio output data left? Consider the sink as being "dirty" then. */ 1894 { 1895 /* Set dirty bit. */ 1896 pSink->fStatus |= AUDMIXSINK_STS_DIRTY; 1897 } 1898 #else 1899 rc = audioMixerSinkWriteToStreams(pSink, enmOp, pvBuf, cbBuf, NULL /* pcbWrittenMin */); 1900 #endif /* VBOX_AUDIO_MIXER_WITH_MIXBUF */ 1985 Assert(cbWritten == cbBuf); 1901 1986 1902 1987 /* Update the sink's last written time stamp. */ … … 1904 1989 1905 1990 if (pcbWritten) 1906 *pcbWritten = cb Buf; /* Always report everything written, as the backends need to keep up themselves. */1991 *pcbWritten = cbWritten; 1907 1992 1908 1993 int rc2 = RTCritSectLeave(&pSink->CritSect);
Note:
See TracChangeset
for help on using the changeset viewer.