Changeset 73525 in vbox for trunk/src/VBox
- Timestamp:
- Aug 6, 2018 12:33:08 PM (7 years ago)
- svn:sync-xref-src-repo-rev:
- 124152
- Location:
- trunk/src/VBox/Devices/Audio
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Audio/AudioMixer.cpp
r73465 r73525 480 480 LogFlowFuncEnter(); 481 481 482 #ifdef VBOX_AUDIO_MIXER_WITH_MIXBUF 483 /* Make sure only compatible streams are added. */ 484 if (pStream->enmDir == PDMAUDIODIR_IN) 485 { 486 if (DrvAudioHlpPCMPropsAreEqual(&pSink->PCMProps, &pStream->InOut.pIn->Props)) 487 { 488 #ifdef VBOX_AUDIO_MIXER_WITH_MIXBUF 489 /* Chain: Stream (Child) -> Sink (Child) -> Guest (Parent). */ 490 PPDMAUDIOMIXBUF pHstIn = &pStream->InOut.pIn->pHstStrmIn->MixBuf; 491 PPDMAUDIOMIXBUF pGstIn = &pStream->InOut.pIn->MixBuf; 492 493 /* Unlink any former parent from host input. */ 494 AudioMixBufUnlink(pHstIn); 495 496 /* Link host input to this sink as a parent. */ 497 rc = AudioMixBufLinkTo(pHstIn, &pSink->MixBuf); 498 AssertRC(rc); 499 500 /* Unlink any former parent from this sink. */ 501 AudioMixBufUnlink(&pSink->MixBuf); 502 503 /* Link guest input to this sink as a parent. */ 504 rc = AudioMixBufLinkTo(&pSink->MixBuf, pGstIn); 505 AssertRC(rc); 506 # ifdef DEBUG 507 AudioMixBufDbgPrintChain(&pStream->InOut.pIn->MixBuf); 508 # endif 509 #endif /* VBOX_AUDIO_MIXER_WITH_MIXBUF */ 510 } 511 else 512 AssertFailedStmt(rc = VERR_WRONG_TYPE); 513 } 514 else if (pStream->enmDir == PDMAUDIODIR_OUT) 515 { 516 if (DrvAudioHlpPCMPropsAreEqual(&pSink->PCMProps, &pStream->InOut.pOut->Props)) 517 { 518 #ifdef VBOX_AUDIO_MIXER_WITH_MIXBUF 519 /* Chain: Guest (Child) -> Sink (Child) -> Stream (Parent). */ 520 rc = AudioMixBufLinkTo(&pStream->InOut.pOut->pHstStrmOut->MixBuf, &pSink->MixBuf); 521 # ifdef DEBUG 522 AudioMixBufDbgPrintChain(&pSink->MixBuf); 523 # endif 524 #endif /* VBOX_AUDIO_MIXER_WITH_MIXBUF */ 525 } 526 else 527 AssertFailedStmt(rc = VERR_WRONG_TYPE); 528 } 529 else 530 AssertFailedStmt(rc = VERR_NOT_IMPLEMENTED); 531 #else 532 rc = VINF_SUCCESS; 533 #endif 482 /** @todo Check if stream already is assigned to (another) sink. */ 483 484 /* If the sink is running and not in pending disable mode, 485 * make sure that the added stream also is enabled. */ 486 if ( (pSink->fStatus & AUDMIXSINK_STS_RUNNING) 487 && !(pSink->fStatus & AUDMIXSINK_STS_PENDING_DISABLE)) 488 { 489 rc = audioMixerStreamCtlInternal(pStream, PDMAUDIOSTREAMCMD_ENABLE, AUDMIXSTRMCTL_FLAG_NONE); 490 } 534 491 535 492 if (RT_SUCCESS(rc)) 536 493 { 537 /** @todo Check if stream already is assigned to (another) sink. */ 538 539 /* If the sink is running and not in pending disable mode, 540 * make sure that the added stream also is enabled. */ 541 if ( (pSink->fStatus & AUDMIXSINK_STS_RUNNING) 542 && !(pSink->fStatus & AUDMIXSINK_STS_PENDING_DISABLE)) 543 { 544 rc = audioMixerStreamCtlInternal(pStream, PDMAUDIOSTREAMCMD_ENABLE, AUDMIXSTRMCTL_FLAG_NONE); 545 } 546 547 if (RT_SUCCESS(rc)) 548 { 549 /* Apply the sink's combined volume to the stream. */ 550 rc = pStream->pConn->pfnStreamSetVolume(pStream->pConn, pStream->pStream, &pSink->VolumeCombined); 551 AssertRC(rc); 552 } 553 554 if (RT_SUCCESS(rc)) 555 { 556 /* Save pointer to sink the stream is attached to. */ 557 pStream->pSink = pSink; 558 559 /* Append stream to sink's list. */ 560 RTListAppend(&pSink->lstStreams, &pStream->Node); 561 pSink->cStreams++; 562 } 494 /* Apply the sink's combined volume to the stream. */ 495 rc = pStream->pConn->pfnStreamSetVolume(pStream->pConn, pStream->pStream, &pSink->VolumeCombined); 496 AssertRC(rc); 497 } 498 499 if (RT_SUCCESS(rc)) 500 { 501 /* Save pointer to sink the stream is attached to. */ 502 pStream->pSink = pSink; 503 504 /* Append stream to sink's list. */ 505 RTListAppend(&pSink->lstStreams, &pStream->Node); 506 pSink->cStreams++; 563 507 } 564 508 … … 859 803 if (pSink->fStatus & AUDMIXSINK_STS_RUNNING) 860 804 { 861 #ifdef VBOX_AUDIO_MIXER_WITH_MIXBUF 805 #ifdef VBOX_AUDIO_MIXER_WITH_MIXBUF_IN 862 806 # error "Implement me!" 863 807 #else … … 922 866 return 0; 923 867 924 const uint64_t deltaLastReadWriteNs = RTTimeNanoTS() - pSink->tsLastReadWrittenNs;925 926 868 uint32_t cbWritable = 0; 927 869 … … 930 872 { 931 873 #ifdef VBOX_AUDIO_MIXER_WITH_MIXBUF 932 # error "Implement me!" 874 cbWritable = AudioMixBufFreeBytes(&pSink->MixBuf); 933 875 #else 934 876 /* Return how much data we expect since the last write. */ 935 cbWritable = DrvAudioHlp NanoToBytes(deltaLastReadWriteNs, &pSink->PCMProps);936 877 cbWritable = DrvAudioHlpMilliToBytes(10 /* ms */, &pSink->PCMProps); /** @todo Make this configurable! */ 878 #endif 937 879 /* Make sure to align the writable size to the stream's frame size. */ 938 880 cbWritable = DrvAudioHlpBytesAlign(cbWritable, &pSink->PCMProps); 939 #endif 940 } 941 942 Log3Func(("Mixer: [%s] cbWritable=%RU32 (%RU64ms)\n", pSink->pszName, cbWritable, deltaLastReadWriteNs / RT_NS_1MS_64));881 } 882 883 Log3Func(("Mixer: [%s] cbWritable=%RU32 (%RU64ms)\n", 884 pSink->pszName, cbWritable, DrvAudioHlpBytesToMilli(cbWritable, &pSink->PCMProps))); 943 885 944 886 int rc2 = RTCritSectLeave(&pSink->CritSect); … … 1131 1073 uint32_t cbReadStrm; 1132 1074 AssertPtr(pStreamRecSource->pConn); 1133 #ifdef VBOX_AUDIO_MIXER_WITH_MIXBUF 1075 #ifdef VBOX_AUDIO_MIXER_WITH_MIXBUF_IN 1134 1076 # error "Implement me!" 1135 1077 #else … … 1209 1151 pSink->pszName, pStream->pStream->szName, pSink->cStreams)); 1210 1152 1211 #ifdef VBOX_AUDIO_MIXER_WITH_MIXBUF1212 /* Unlink mixing buffer. */1213 AudioMixBufUnlink(&pStream->pStream->MixBuf);1214 #endif1215 1216 1153 /* Remove stream from sink. */ 1217 1154 RTListNodeRemove(&pStream->Node); … … 1284 1221 LogFunc(("[%s]\n", pSink->pszName)); 1285 1222 1286 if (pSink->enmDir == AUDMIXSINKDIR_INPUT)1287 {1288 1223 #ifdef VBOX_AUDIO_MIXER_WITH_MIXBUF 1289 AudioMixBufReset(&pSink->MixBuf); 1290 #else 1291 pSink->In.cbReadable = 0; 1224 AudioMixBufReset(&pSink->MixBuf); 1292 1225 #endif 1293 }1294 else if (pSink->enmDir == AUDMIXSINKDIR_OUTPUT)1295 {1296 #ifdef VBOX_AUDIO_MIXER_WITH_MIXBUF1297 AudioMixBufReset(&pSink->MixBuf);1298 #else1299 pSink->Out.cbWritable = 0;1300 #endif1301 }1302 1226 1303 1227 /* Update last updated timestamp. */ 1304 pSink->tsLastUpdatedMs = RTTimeMilliTS();1228 pSink->tsLastUpdatedMs = 0; 1305 1229 1306 1230 /* Reset status. */ … … 1408 1332 /* Also update the sink's mixing buffer format. */ 1409 1333 AudioMixBufDestroy(&pSink->MixBuf); 1410 rc = AudioMixBufInit(&pSink->MixBuf, pSink->pszName, pPCMProps, _4K /** @todo Make configurable? */); 1334 rc = AudioMixBufInit(&pSink->MixBuf, pSink->pszName, &pSink->PCMProps, 1335 DrvAudioHlpMilliToFrames(100 /* ms */, &pSink->PCMProps)); /** @todo Make this configurable? */ 1411 1336 if (RT_SUCCESS(rc)) 1412 1337 { … … 1632 1557 } 1633 1558 1634 Log3Func(("[%s] cbReadable=%RU32, cbWritable=%RU32, rc=%Rrc\n",1635 pSink->pszName, pSink->In.cbReadable, pSink->Out.cbWritable, rc));1636 1637 1559 return rc; 1638 1560 } … … 1702 1624 1703 1625 /** 1704 * Writes data to a mixer sink.1626 * Writes audio output data to all connected mixer streams (multiplex). 1705 1627 * 1706 1628 * @returns IPRT status code. 1707 * @param pSink Sink to write data to. 1708 * @param enmOp Mixer operation to use when writing data to the sink. 1709 * @param pvBuf Buffer containing the audio data to write. 1710 * @param cbBuf Size (in bytes) of the buffer containing the audio data. 1711 * @param pcbWritten Number of bytes written. Optional. 1712 */ 1713 int AudioMixerSinkWrite(PAUDMIXSINK pSink, AUDMIXOP enmOp, const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten) 1714 { 1715 AssertPtrReturn(pSink, VERR_INVALID_POINTER); 1629 * @param pSink Sink to write audio output to. 1630 * @param enmOp What mixing operation to use. Currently not implemented. 1631 * @param pvBuf Pointer to audio data to write. 1632 * @param cbBuf Size (in bytes) of audio data to write. 1633 * @param pcbWrittenMin Returns minimum size (in bytes) successfully written by all mixer streams. Optional. 1634 */ 1635 int audioMixerSinkWriteToStreams(PAUDMIXSINK pSink, AUDMIXOP enmOp, const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWrittenMin) 1636 { 1716 1637 RT_NOREF(enmOp); 1717 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER); 1718 AssertReturn (cbBuf, VERR_INVALID_PARAMETER); 1719 /* pcbWritten is optional. */ 1720 1721 int rc = RTCritSectEnter(&pSink->CritSect); 1722 if (RT_FAILURE(rc)) 1723 return rc; 1724 1725 AssertMsg(pSink->fStatus & AUDMIXSINK_STS_RUNNING, 1726 ("%s: Can't write to a sink which is not running (anymore) (status 0x%x)\n", pSink->pszName, pSink->fStatus)); 1727 AssertMsg(pSink->enmDir == AUDMIXSINKDIR_OUTPUT, 1728 ("%s: Can't write to a sink which is not an output sink\n", pSink->pszName)); 1638 1639 int rc = VINF_SUCCESS; 1640 1641 uint32_t cbWrittenMin = UINT32_MAX; 1729 1642 1730 1643 PAUDMIXSTREAM pMixStream; … … 1760 1673 LogFunc(("[%s] Warning: Only written %RU32/%RU32 bytes for stream '%s'\n", 1761 1674 pSink->pszName, cbWritten, cbBuf, pMixStream->pszName)); 1762 LogRel2(("Audio: Buffer overrun for mixer s ink '%s', stream '%s'\n", pSink->pszName, pMixStream->pszName));1675 LogRel2(("Audio: Buffer overrun for mixer stream '%s' (sink '%s')\n", pMixStream->pszName, pSink->pszName)); 1763 1676 #ifdef DEBUG_andy 1764 1677 AssertFailed(); 1765 1678 #endif 1766 1679 } 1680 1681 cbWrittenMin = RT_MIN(cbWrittenMin, cbWritten); 1767 1682 1768 1683 if (cbWritten) /* Update the mixer stream's last written time stamp. */ … … 1804 1719 cbToWrite -= (uint32_t)cbChunk; 1805 1720 } 1806 1807 if (RTCircBufUsed(pCircBuf)) 1808 { 1809 /* Set dirty bit. */ 1810 pSink->fStatus |= AUDMIXSINK_STS_DIRTY; 1811 } 1812 } 1721 } 1722 1723 if (cbWrittenMin == UINT32_MAX) /* Nothing written? */ 1724 cbWrittenMin = 0; 1725 1726 if (pcbWrittenMin) 1727 *pcbWrittenMin = cbWrittenMin; 1728 1729 return rc; 1730 } 1731 1732 /** 1733 * Writes data to a mixer sink. 1734 * 1735 * @returns IPRT status code. 1736 * @param pSink Sink to write data to. 1737 * @param enmOp Mixer operation to use when writing data to the sink. 1738 * @param pvBuf Buffer containing the audio data to write. 1739 * @param cbBuf Size (in bytes) of the buffer containing the audio data. 1740 * @param pcbWritten Number of bytes written. Optional. 1741 */ 1742 int AudioMixerSinkWrite(PAUDMIXSINK pSink, AUDMIXOP enmOp, const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten) 1743 { 1744 AssertPtrReturn(pSink, VERR_INVALID_POINTER); 1745 RT_NOREF(enmOp); 1746 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER); 1747 AssertReturn (cbBuf, VERR_INVALID_PARAMETER); 1748 /* pcbWritten is optional. */ 1749 1750 int rc = RTCritSectEnter(&pSink->CritSect); 1751 if (RT_FAILURE(rc)) 1752 return rc; 1753 1754 AssertMsg(pSink->fStatus & AUDMIXSINK_STS_RUNNING, 1755 ("%s: Can't write to a sink which is not running (anymore) (status 0x%x)\n", pSink->pszName, pSink->fStatus)); 1756 AssertMsg(pSink->enmDir == AUDMIXSINKDIR_OUTPUT, 1757 ("%s: Can't write to a sink which is not an output sink\n", pSink->pszName)); 1758 1759 #ifdef VBOX_AUDIO_MIXER_WITH_MIXBUF 1760 uint32_t cbWritten = 0; 1761 uint32_t cbToWrite = cbBuf; 1762 while (cbToWrite) 1763 { 1764 /* First, write the data to the mixer sink's own mixing buffer. 1765 * Here the audio data can be transformed into the mixer sink's format. */ 1766 uint32_t cfWritten = 0; 1767 rc = AudioMixBufWriteCirc(&pSink->MixBuf, (uint8_t *)pvBuf + cbWritten, cbToWrite, &cfWritten); 1768 if (RT_FAILURE(rc)) 1769 break; 1770 1771 const uint32_t cbWrittenChunk = DrvAudioHlpFramesToBytes(cfWritten, &pSink->PCMProps); 1772 1773 Assert(cbToWrite >= cbWrittenChunk); 1774 cbToWrite -= cbWrittenChunk; 1775 cbWritten += cbWrittenChunk; 1776 } 1777 1778 Assert(cbWritten <= cbBuf); 1779 1780 if ( RT_FAILURE(rc) 1781 || cbWritten < cbBuf) 1782 { 1783 LogRel2(("Audio: Buffer overrun for mixer sink '%s' (only %RU32/%RU32 bytes written)\n", 1784 pSink->pszName, cbWritten, cbBuf)); 1785 # ifdef DEBUG_andy 1786 AssertFailed(); 1787 # endif 1788 } 1789 1790 /* Next, try to write (multiplex) as much audio data as possible to all connected mixer streams. */ 1791 uint8_t arrChunkBuf[_1K]; /** @todo Hm ... some zero copy / shared buffers would be nice! */ 1792 while (cbWritten) 1793 { 1794 uint32_t cfChunk; 1795 rc = AudioMixBufAcquireReadBlock(&pSink->MixBuf, arrChunkBuf, sizeof(arrChunkBuf), &cfChunk); 1796 if (RT_FAILURE(rc)) 1797 break; 1798 1799 const uint32_t cbChunk = DrvAudioHlpFramesToBytes(cfChunk, &pSink->PCMProps); 1800 Assert(cbChunk <= sizeof(arrChunkBuf)); 1801 rc = audioMixerSinkWriteToStreams(pSink, enmOp, arrChunkBuf, cbChunk, NULL /* pcbWrittenMin */); 1802 AudioMixBufReleaseReadBlock(&pSink->MixBuf, cfChunk); 1803 1804 Assert(cbWritten >= cbChunk); 1805 cbWritten -= cbChunk; 1806 } 1807 1808 if ( !(pSink->fStatus & AUDMIXSINK_STS_DIRTY) 1809 && AudioMixBufUsed(&pSink->MixBuf)) /* Still audio output data left? Consider the sink as being "dirty" then. */ 1810 { 1811 /* Set dirty bit. */ 1812 pSink->fStatus |= AUDMIXSINK_STS_DIRTY; 1813 } 1814 #else 1815 rc = audioMixerSinkWriteToStreams(pSink, enmOp, pvBuf, cbBuf, NULL /* pcbWrittenMin */); 1816 #endif /* VBOX_AUDIO_MIXER_WITH_MIXBUF */ 1813 1817 1814 1818 /* Update the sink's last written time stamp. */ -
trunk/src/VBox/Devices/Audio/AudioMixer.h
r73421 r73525 26 26 27 27 #include <VBox/vmm/pdmaudioifs.h> 28 29 /* Use a mixer sink's mixing buffer for multiplexing. */ 30 #define VBOX_AUDIO_MIXER_WITH_MIXBUF 28 31 29 32 /** … … 136 139 typedef struct AUDMIXSINKIN 137 140 { 138 #ifdef VBOX_AUDIO_MIXER_WITH_MIXBUF139 /** This sink's mixing buffer, acting as140 * a parent buffer for all streams this sink owns. */141 PDMAUDIOMIXBUF MixBuf;142 #else143 /** Number of bytes available to read from the sink. */144 uint32_t cbReadable;145 #endif146 141 /** The current recording source. Can be NULL if not set. */ 147 142 PAUDMIXSTREAM pStreamRecSource; … … 154 149 typedef struct AUDMIXSINKOUT 155 150 { 156 #ifdef VBOX_AUDIO_MIXER_WITH_MIXBUF157 /** This sink's mixing buffer, acting as158 * a parent buffer for all streams this sink owns. */159 PDMAUDIOMIXBUF MixBuf;160 #else161 /** Number of bytes available to write to the sink. */162 uint32_t cbWritable;163 #endif164 151 } AUDMIXSINKOUT; 165 152 … … 179 166 /** The sink's critical section. */ 180 167 RTCRITSECT CritSect; 168 #ifdef VBOX_AUDIO_MIXER_WITH_MIXBUF 169 /** This sink's mixing buffer, acting as 170 * a parent buffer for all streams this sink owns. */ 171 PDMAUDIOMIXBUF MixBuf; 172 #endif 181 173 /** Union for input/output specifics. */ 182 174 union
Note:
See TracChangeset
for help on using the changeset viewer.