Changeset 89439 in vbox for trunk/src/VBox/ValidationKit
- Timestamp:
- Jun 1, 2021 7:41:40 PM (4 years ago)
- Location:
- trunk/src/VBox/ValidationKit/utils/audio
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/ValidationKit/utils/audio/vkat.cpp
r89436 r89439 170 170 typedef AUDIOTESTSTREAM *PAUDIOTESTSTREAM; 171 171 172 /** Maximum audio streams a test environment can handle. */ 173 #define AUDIOTESTENV_MAX_STREAMS 8 174 172 175 /** 173 176 * Audio test environment parameters. … … 1644 1647 1645 1648 /** 1649 * Worker for audioTestPlayOne. 1650 */ 1651 static RTEXITCODE audioTestPlayOneInner(PAUDIOTESTDRVMIXSTREAM pMix, PAUDIOTESTWAVEFILE pWaveFile, 1652 PCPDMAUDIOSTREAMCFG pCfgAcq, const char *pszFile) 1653 { 1654 uint32_t const cbPreBuffer = PDMAudioPropsFramesToBytes(pMix->pProps, pCfgAcq->Backend.cFramesPreBuffering); 1655 uint64_t const nsStarted = RTTimeNanoTS(); 1656 1657 /* 1658 * Transfer data as quickly as we're allowed. 1659 */ 1660 uint8_t abSamples[16384]; 1661 uint32_t const cbSamplesAligned = PDMAudioPropsFloorBytesToFrame(pMix->pProps, sizeof(abSamples)); 1662 uint64_t offStream = 0; 1663 for (;;) 1664 { 1665 /* Read a chunk from the wave file. */ 1666 size_t cbSamples = 0; 1667 int rc = AudioTestWaveFileRead(pWaveFile, abSamples, cbSamplesAligned, &cbSamples); 1668 if (RT_SUCCESS(rc) && cbSamples > 0) 1669 { 1670 /* Pace ourselves a little. */ 1671 if (offStream >= cbPreBuffer) 1672 { 1673 uint64_t const cNsWritten = PDMAudioPropsBytesToNano64(pMix->pProps, offStream); 1674 uint64_t const cNsElapsed = RTTimeNanoTS() - nsStarted; 1675 if (cNsWritten + RT_NS_10MS > cNsElapsed) 1676 RTThreadSleep((cNsWritten - cNsElapsed - RT_NS_10MS / 2) / RT_NS_1MS); 1677 } 1678 1679 /* Transfer the data to the audio stream. */ 1680 for (uint32_t offSamples = 0; offSamples < cbSamples;) 1681 { 1682 uint32_t const cbCanWrite = AudioTestMixStreamGetWritable(pMix); 1683 if (cbCanWrite > 0) 1684 { 1685 uint32_t const cbToPlay = RT_MIN(cbCanWrite, (uint32_t)cbSamples - offSamples); 1686 uint32_t cbPlayed = 0; 1687 rc = AudioTestMixStreamPlay(pMix, &abSamples[offSamples], cbToPlay, &cbPlayed); 1688 if (RT_SUCCESS(rc)) 1689 { 1690 if (cbPlayed) 1691 { 1692 offSamples += cbPlayed; 1693 offStream += cbPlayed; 1694 } 1695 else 1696 return RTMsgErrorExitFailure("Played zero out of %#x bytes - %#x bytes reported playable!\n", 1697 cbToPlay, cbCanWrite); 1698 } 1699 else 1700 return RTMsgErrorExitFailure("Failed to play %#x bytes: %Rrc\n", cbToPlay, rc); 1701 } 1702 else if (AudioTestMixStreamIsOkay(pMix)) 1703 RTThreadSleep(RT_MIN(RT_MAX(1, pCfgAcq->Device.cMsSchedulingHint), 256)); 1704 else 1705 return RTMsgErrorExitFailure("Stream is not okay!\n"); 1706 } 1707 } 1708 else if (RT_SUCCESS(rc) && cbSamples == 0) 1709 break; 1710 else 1711 return RTMsgErrorExitFailure("Error reading wav file '%s': %Rrc", pszFile, rc); 1712 } 1713 1714 /* 1715 * Drain the stream. 1716 */ 1717 if (g_uVerbosity > 0) 1718 RTMsgInfo("%'RU64 ns: Draining...\n", RTTimeNanoTS() - nsStarted); 1719 int rc = AudioTestMixStreamDrain(pMix, true /*fSync*/); 1720 if (RT_SUCCESS(rc)) 1721 { 1722 if (g_uVerbosity > 0) 1723 RTMsgInfo("%'RU64 ns: Done\n", RTTimeNanoTS() - nsStarted); 1724 } 1725 else 1726 return RTMsgErrorExitFailure("Draining failed: %Rrc", rc); 1727 1728 return RTEXITCODE_SUCCESS; 1729 } 1730 1731 1732 /** 1646 1733 * Worker for audioTestCmdPlayHandler that plays one file. 1647 1734 */ 1648 1735 static RTEXITCODE audioTestPlayOne(const char *pszFile, PCPDMDRVREG pDrvReg, const char *pszDevId, uint32_t cMsBufferSize, 1649 uint32_t cMsPreBuffer, uint32_t cMsSchedulingHint, bool fWithDrvAudio) 1650 { 1736 uint32_t cMsPreBuffer, uint32_t cMsSchedulingHint, 1737 uint8_t cChannels, uint8_t cbSample, uint32_t uHz, 1738 bool fWithDrvAudio, bool fWithMixer) 1739 { 1740 char szTmp[128]; 1741 1651 1742 /* 1652 1743 * First we must open the file and determin the format. … … 1660 1751 if (g_uVerbosity > 0) 1661 1752 { 1662 char szTmp[128];1663 1753 RTMsgInfo("Opened '%s' for playing\n", pszFile); 1664 1754 RTMsgInfo("Format: %s\n", PDMAudioPropsToString(&WaveFile.Props, szTmp, sizeof(szTmp))); … … 1686 1776 * Open a stream for the output. 1687 1777 */ 1778 PDMAUDIOPCMPROPS ReqProps = WaveFile.Props; 1779 if (cChannels != 0 && PDMAudioPropsChannels(&ReqProps) != cChannels) 1780 PDMAudioPropsSetChannels(&ReqProps, cChannels); 1781 if (cbSample != 0) 1782 PDMAudioPropsSetSampleSize(&ReqProps, cbSample); 1783 if (uHz != 0) 1784 ReqProps.uHz = uHz; 1785 1688 1786 PDMAUDIOSTREAMCFG CfgAcq; 1689 PPDMAUDIOSTREAM pStream = NULL;1690 rc = audioTestDriverStackStreamCreateOutput(&DrvStack, & WaveFile.Props, cMsBufferSize,1787 PPDMAUDIOSTREAM pStream = NULL; 1788 rc = audioTestDriverStackStreamCreateOutput(&DrvStack, &ReqProps, cMsBufferSize, 1691 1789 cMsPreBuffer, cMsSchedulingHint, &pStream, &CfgAcq); 1692 1790 if (RT_SUCCESS(rc)) 1693 1791 { 1694 rc = audioTestDriverStackStreamEnable(&DrvStack, pStream); 1792 AUDIOTESTDRVMIXSTREAM Mix; 1793 rc = AudioTestMixStreamInit(&Mix, &DrvStack, pStream, fWithMixer ? &WaveFile.Props : NULL, 100 /*ms*/); 1695 1794 if (RT_SUCCESS(rc)) 1696 1795 { 1697 uint32_t const cbPreBuffer = PDMAudioPropsFramesToBytes(&pStream->Props, CfgAcq.Backend.cFramesPreBuffering); 1698 uint64_t const nsStarted = RTTimeNanoTS(); 1699 1700 /* 1701 * Transfer data as quickly as we're allowed. 1702 */ 1703 uint8_t abSamples[16384]; 1704 uint32_t const cbSamplesAligned = PDMAudioPropsFloorBytesToFrame(&pStream->Props, sizeof(abSamples)); 1705 uint64_t offStream = 0; 1706 for (;;) 1707 { 1708 /* Read a chunk from the wave file. */ 1709 size_t cbSamples = 0; 1710 rc = AudioTestWaveFileRead(&WaveFile, abSamples, cbSamplesAligned, &cbSamples); 1711 if (RT_SUCCESS(rc) && cbSamples > 0) 1712 { 1713 /* Pace ourselves a little. */ 1714 if (offStream >= cbPreBuffer) 1715 { 1716 uint64_t const cNsWritten = PDMAudioPropsBytesToNano(&pStream->Props, offStream); 1717 uint64_t const cNsElapsed = RTTimeNanoTS() - nsStarted; 1718 if (cNsWritten + RT_NS_10MS > cNsElapsed) 1719 RTThreadSleep((cNsWritten - cNsElapsed - RT_NS_10MS / 2) / RT_NS_1MS); 1720 } 1721 1722 /* Transfer the data to the audio stream. */ 1723 for (uint32_t offSamples = 0; offSamples < cbSamples;) 1724 { 1725 uint32_t const cbCanWrite = audioTestDriverStackStreamGetWritable(&DrvStack, pStream); 1726 if (cbCanWrite > 0) 1727 { 1728 uint32_t const cbToPlay = RT_MIN(cbCanWrite, (uint32_t)cbSamples - offSamples); 1729 uint32_t cbPlayed = 0; 1730 rc = audioTestDriverStackStreamPlay(&DrvStack, pStream, &abSamples[offSamples], 1731 cbToPlay, &cbPlayed); 1732 if (RT_SUCCESS(rc)) 1733 { 1734 if (cbPlayed) 1735 { 1736 offSamples += cbPlayed; 1737 offStream += cbPlayed; 1738 } 1739 else 1740 { 1741 rcExit = RTMsgErrorExitFailure("Played zero out of %#x bytes - %#x bytes reported playable!\n", 1742 cbToPlay, cbCanWrite); 1743 break; 1744 } 1745 } 1746 else 1747 { 1748 rcExit = RTMsgErrorExitFailure("Failed to play %#x bytes: %Rrc\n", cbToPlay, rc); 1749 break; 1750 } 1751 } 1752 else if (audioTestDriverStackStreamIsOkay(&DrvStack, pStream)) 1753 RTThreadSleep(RT_MIN(RT_MAX(1, CfgAcq.Device.cMsSchedulingHint), 256)); 1754 else 1755 { 1756 rcExit = RTMsgErrorExitFailure("Stream is not okay!\n"); 1757 break; 1758 } 1759 } 1760 } 1761 else if (RT_SUCCESS(rc) && cbSamples == 0) 1762 { 1763 rcExit = RTEXITCODE_SUCCESS; 1764 break; 1765 } 1766 else 1767 { 1768 rcExit = RTMsgErrorExitFailure("Error reading wav file '%s': %Rrc", pszFile, rc); 1769 break; 1770 } 1771 } 1772 1773 /* 1774 * Drain the stream. 1775 */ 1776 if (rcExit == RTEXITCODE_SUCCESS) 1777 { 1778 if (g_uVerbosity > 0) 1779 RTMsgInfo("%'RU64 ns: Draining...\n", RTTimeNanoTS() - nsStarted); 1780 rc = audioTestDriverStackStreamDrain(&DrvStack, pStream, true /*fSync*/); 1781 if (RT_SUCCESS(rc)) 1782 { 1783 if (g_uVerbosity > 0) 1784 RTMsgInfo("%'RU64 ns: Done\n", RTTimeNanoTS() - nsStarted); 1785 } 1786 else 1787 rcExit = RTMsgErrorExitFailure("Draining failed: %Rrc", rc); 1788 } 1796 if (g_uVerbosity > 0) 1797 RTMsgInfo("Stream: %s cbBacked=%#RX32%s\n", PDMAudioPropsToString(&pStream->Props, szTmp, sizeof(szTmp)), 1798 pStream->cbBackend, fWithMixer ? " mixed" : ""); 1799 1800 rc = audioTestDriverStackStreamEnable(&DrvStack, pStream); 1801 if (RT_SUCCESS(rc)) 1802 rcExit = audioTestPlayOneInner(&Mix, &WaveFile, &CfgAcq, pszFile); 1803 else 1804 rcExit = RTMsgErrorExitFailure("Enabling the output stream failed: %Rrc", rc); 1789 1805 } 1790 else1791 rcExit = RTMsgErrorExitFailure("Enabling the output stream failed: %Rrc", rc);1792 1806 audioTestDriverStackStreamDestroy(&DrvStack, pStream); 1793 1807 } … … 1811 1825 { 1812 1826 { "--backend", 'b', RTGETOPT_REQ_STRING }, 1827 { "--channels", 'c', RTGETOPT_REQ_UINT8 }, 1828 { "--hz", 'f', RTGETOPT_REQ_UINT32 }, 1829 { "--frequency", 'f', RTGETOPT_REQ_UINT32 }, 1830 { "--sample-size", 'z', RTGETOPT_REQ_UINT8 }, 1813 1831 { "--output-device", 'o', RTGETOPT_REQ_STRING }, 1814 1832 { "--with-drv-audio", 'd', RTGETOPT_REQ_NOTHING }, 1833 { "--with-mixer", 'm', RTGETOPT_REQ_NOTHING }, 1815 1834 }; 1816 1835 … … 1821 1840 { 1822 1841 case 'b': return "The audio backend to use."; 1842 case 'c': return "Number of backend output channels"; 1823 1843 case 'd': return "Go via DrvAudio instead of directly interfacing with the backend."; 1844 case 'f': return "Output frequency (Hz)"; 1845 case 'z': return "Output sample size (bits)"; 1846 case 'm': return "Go via the mixer."; 1824 1847 case 'o': return "The ID of the output device to use."; 1825 1848 default: return NULL; … … 1836 1859 { 1837 1860 /* Option values: */ 1838 PCPDMDRVREG pDrvReg = g_aBackends[0].pDrvReg; 1839 uint32_t cMsBufferSize = UINT32_MAX; 1840 uint32_t cMsPreBuffer = UINT32_MAX; 1841 uint32_t cMsSchedulingHint = UINT32_MAX; 1842 const char *pszDevId = NULL; 1843 bool fWithDrvAudio = false; 1861 PCPDMDRVREG pDrvReg = g_aBackends[0].pDrvReg; 1862 uint32_t cMsBufferSize = UINT32_MAX; 1863 uint32_t cMsPreBuffer = UINT32_MAX; 1864 uint32_t cMsSchedulingHint = UINT32_MAX; 1865 const char *pszDevId = NULL; 1866 bool fWithDrvAudio = false; 1867 bool fWithMixer = false; 1868 uint8_t cbSample = 0; 1869 uint8_t cChannels = 0; 1870 uint32_t uHz = 0; 1844 1871 1845 1872 /* Argument processing loop: */ … … 1863 1890 break; 1864 1891 1892 case 'c': 1893 cChannels = ValueUnion.u8; 1894 break; 1895 1865 1896 case 'd': 1866 1897 fWithDrvAudio = true; 1867 1898 break; 1868 1899 1900 case 'f': 1901 uHz = ValueUnion.u32; 1902 break; 1903 1904 case 'm': 1905 fWithMixer = true; 1906 break; 1907 1869 1908 case 'o': 1870 1909 pszDevId = ValueUnion.psz; 1910 break; 1911 1912 case 'z': 1913 cbSample = ValueUnion.u8 / 8; 1871 1914 break; 1872 1915 … … 1874 1917 { 1875 1918 RTEXITCODE rcExit = audioTestPlayOne(ValueUnion.psz, pDrvReg, pszDevId, cMsBufferSize, cMsPreBuffer, 1876 cMsSchedulingHint, fWithDrvAudio);1919 cMsSchedulingHint, cChannels, cbSample, uHz, fWithDrvAudio, fWithMixer); 1877 1920 if (rcExit != RTEXITCODE_SUCCESS) 1878 1921 return rcExit; … … 1888 1931 return RTEXITCODE_SUCCESS; 1889 1932 } 1933 1934 1935 /********************************************************************************************************************************* 1936 * Command: selftest * 1937 *********************************************************************************************************************************/ 1890 1938 1891 1939 /** -
trunk/src/VBox/ValidationKit/utils/audio/vkatDriverStack.cpp
r89417 r89439 49 49 50 50 #include "vkatInternal.h" 51 #include "VBoxDD.h" 51 52 52 53 … … 69 70 return NULL; 70 71 } 72 71 73 72 74 VMMR3DECL(int) CFGMR3QueryString(PCFGMNODE pNode, const char *pszName, char *pszString, size_t cchString) … … 93 95 } 94 96 97 95 98 VMMR3DECL(int) CFGMR3QueryStringAlloc(PCFGMNODE pNode, const char *pszName, char **ppszString) 96 99 { … … 103 106 } 104 107 108 105 109 VMMR3DECL(void) MMR3HeapFree(void *pv) 106 110 { … … 108 112 RTStrFree((char *)pv); 109 113 } 114 110 115 111 116 VMMR3DECL(int) CFGMR3QueryStringDef(PCFGMNODE pNode, const char *pszName, char *pszString, size_t cchString, const char *pszDef) … … 133 138 } 134 139 140 135 141 VMMR3DECL(int) CFGMR3QueryBoolDef(PCFGMNODE pNode, const char *pszName, bool *pf, bool fDef) 136 142 { … … 151 157 } 152 158 159 153 160 VMMR3DECL(int) CFGMR3QueryU8(PCFGMNODE pNode, const char *pszName, uint8_t *pu8) 154 161 { … … 157 164 } 158 165 166 159 167 VMMR3DECL(int) CFGMR3QueryU32(PCFGMNODE pNode, const char *pszName, uint32_t *pu32) 160 168 { … … 162 170 return VERR_CFGM_VALUE_NOT_FOUND; 163 171 } 172 164 173 165 174 VMMR3DECL(int) CFGMR3ValidateConfig(PCFGMNODE pNode, const char *pszNode, … … 201 210 } 202 211 212 203 213 static DECLCALLBACK(void) audioTestDrvHlp_STAMRegisterF(PPDMDRVINS pDrvIns, void *pvSample, STAMTYPE enmType, 204 214 STAMVISIBILITY enmVisibility, STAMUNIT enmUnit, const char *pszDesc, … … 208 218 } 209 219 220 210 221 static DECLCALLBACK(void) audioTestDrvHlp_STAMRegisterV(PPDMDRVINS pDrvIns, void *pvSample, STAMTYPE enmType, 211 222 STAMVISIBILITY enmVisibility, STAMUNIT enmUnit, const char *pszDesc, … … 215 226 } 216 227 228 217 229 static DECLCALLBACK(int) audioTestDrvHlp_STAMDeregister(PPDMDRVINS pDrvIns, void *pvSample) 218 230 { … … 220 232 return VINF_SUCCESS; 221 233 } 234 222 235 223 236 static DECLCALLBACK(int) audioTestDrvHlp_STAMDeregisterByPrefix(PPDMDRVINS pDrvIns, const char *pszPrefix) … … 279 292 } 280 293 294 281 295 DECLCALLBACK(void) audioTestIHostAudioPort_NotifyDeviceChanged(PPDMIHOSTAUDIOPORT pInterface, PDMAUDIODIR enmDir, void *pvUser) 282 296 { … … 285 299 } 286 300 301 287 302 static DECLCALLBACK(void) audioTestIHostAudioPort_StreamNotifyPreparingDeviceSwitch(PPDMIHOSTAUDIOPORT pInterface, 288 303 PPDMAUDIOBACKENDSTREAM pStream) … … 292 307 } 293 308 309 294 310 static DECLCALLBACK(void) audioTestIHostAudioPort_StreamNotifyDeviceChanged(PPDMIHOSTAUDIOPORT pInterface, 295 311 PPDMAUDIOBACKENDSTREAM pStream, bool fReInit) … … 299 315 } 300 316 317 301 318 static DECLCALLBACK(void) audioTestIHostAudioPort_NotifyDevicesChanged(PPDMIHOSTAUDIOPORT pInterface) 302 319 { … … 304 321 RTMsgWarning("audioTestIHostAudioPort_NotifyDevicesChanged was called\n"); 305 322 } 323 306 324 307 325 static PDMIHOSTAUDIOPORT g_AudioTestIHostAudioPort = … … 314 332 }; 315 333 334 316 335 /** 317 336 * Implementation of PDMIBASE::pfnQueryInterface for a fake DrvAudio above a … … 325 344 return NULL; 326 345 } 346 327 347 328 348 /** IBase interface for a fake DrvAudio above a lonesome backend. */ … … 397 417 } 398 418 419 399 420 /** 400 421 * Destructs a PDM audio driver instance. … … 417 438 } 418 439 440 419 441 /** 420 442 * Sends the PDM driver a power off notification. … … 432 454 } 433 455 456 434 457 /** 435 458 * Deletes a driver stack. … … 456 479 pDrvStack->pIAudioConnector = NULL; 457 480 } 481 458 482 459 483 /** … … 467 491 int audioTestDriverStackInit(PAUDIOTESTDRVSTACK pDrvStack, PCPDMDRVREG pDrvReg, bool fWithDrvAudio) 468 492 { 493 int rc; 494 469 495 RT_ZERO(*pDrvStack); 470 496 pDrvStack->pDrvReg = pDrvReg; 471 497 472 int rc;473 498 if (!fWithDrvAudio) 474 499 rc = audioTestDrvConstruct(pDrvStack, pDrvReg, NULL /*pParentDrvIns*/, &pDrvStack->pDrvBackendIns); … … 525 550 } 526 551 552 527 553 /** 528 554 * Wrapper around PDMIHOSTAUDIO::pfnSetDevice. … … 541 567 } 542 568 569 543 570 /** 544 571 * Common stream creation code. 545 572 * 546 573 * @returns VBox status code. 547 * @param pDrvStack The audio driver stack to create it via. 548 * @param pCfgReq The requested config. 549 * @param ppStream Where to return the stream pointer on success. 550 * @param pCfgAcq Where to return the actual (well, not 551 * necessarily when using DrvAudio, but probably 552 * the same) stream config on success (not used as 553 * input). 574 * @param pDrvStack The audio driver stack to create it via. 575 * @param pCfgReq The requested config. 576 * @param ppStream Where to return the stream pointer on success. 577 * @param pCfgAcq Where to return the actual (well, not necessarily when 578 * using DrvAudio, but probably the same) stream config on 579 * success (not used as input). 554 580 */ 555 581 static int audioTestDriverStackStreamCreate(PAUDIOTESTDRVSTACK pDrvStack, PPDMAUDIOSTREAMCFG pCfgReq, … … 670 696 } 671 697 698 672 699 /** 673 700 * Creates an output stream. … … 729 756 } 730 757 758 731 759 /** 732 760 * Creates an input stream. … … 788 816 } 789 817 818 790 819 /** 791 820 * Destroys a stream. … … 817 846 } 818 847 848 819 849 /** 820 850 * Enables a stream. … … 838 868 return rc; 839 869 } 870 871 872 /** 873 * Disables a stream. 874 */ 875 int AudioTestDriverStackStreamDisable(PAUDIOTESTDRVSTACK pDrvStack, PPDMAUDIOSTREAM pStream) 876 { 877 int rc; 878 if (pDrvStack->pIAudioConnector) 879 { 880 rc = pDrvStack->pIAudioConnector->pfnStreamControl(pDrvStack->pIAudioConnector, pStream, PDMAUDIOSTREAMCMD_DISABLE); 881 if (RT_FAILURE(rc)) 882 RTTestFailed(g_hTest, "pfnStreamControl/DISABLE failed: %Rrc", rc); 883 } 884 else 885 { 886 PAUDIOTESTDRVSTACKSTREAM pStreamAt = (PAUDIOTESTDRVSTACKSTREAM)pStream; 887 rc = pDrvStack->pIHostAudio->pfnStreamControl(pDrvStack->pIHostAudio, &pStreamAt->Backend, PDMAUDIOSTREAMCMD_DISABLE); 888 if (RT_FAILURE(rc)) 889 RTTestFailed(g_hTest, "PDMIHOSTAUDIO::pfnStreamControl/DISABLE failed: %Rrc", rc); 890 } 891 return rc; 892 } 893 840 894 841 895 /** … … 921 975 } 922 976 977 923 978 /** 924 979 * Checks if the stream is okay. … … 977 1032 } 978 1033 1034 979 1035 /** 980 1036 * Gets the number of bytes it's currently possible to write to the stream. … … 992 1048 return cbWritable; 993 1049 } 1050 994 1051 995 1052 /** … … 1016 1073 } 1017 1074 1075 1018 1076 /** 1019 1077 * Tries to capture @a cbBuf bytes of samples in @a pvBuf. … … 1039 1097 } 1040 1098 1099 1100 /********************************************************************************************************************************* 1101 * Mixed streams * 1102 *********************************************************************************************************************************/ 1103 1104 /** 1105 * Initializing mixing for a stream. 1106 * 1107 * This can be used as a do-nothing wrapper for the stack. 1108 * 1109 * @returns VBox status code. 1110 * @param pMix The mixing state. 1111 * @param pStream The stream to mix to/from. 1112 * @param pProps The mixer properties. Pass NULL for no mixing, just 1113 * wrap the driver stack functionality. 1114 * @param cMsBuffer The buffer size. 1115 */ 1116 int AudioTestMixStreamInit(PAUDIOTESTDRVMIXSTREAM pMix, PAUDIOTESTDRVSTACK pDrvStack, PPDMAUDIOSTREAM pStream, 1117 PCPDMAUDIOPCMPROPS pProps, uint32_t cMsBuffer) 1118 { 1119 RT_ZERO(*pMix); 1120 1121 AssertReturn(pDrvStack, VERR_INVALID_PARAMETER); 1122 AssertReturn(pStream, VERR_INVALID_PARAMETER); 1123 1124 pMix->pDrvStack = pDrvStack; 1125 pMix->pStream = pStream; 1126 if (!pProps) 1127 { 1128 pMix->pProps = &pStream->Props; 1129 return VINF_SUCCESS; 1130 } 1131 1132 /* 1133 * Okay, we're doing mixing so we need to set up the mixer buffer 1134 * and associated states. 1135 */ 1136 pMix->fDoMixing = true; 1137 int rc = AudioMixBufInit(&pMix->MixBuf, "mixer", pProps, PDMAudioPropsMilliToFrames(pProps, cMsBuffer)); 1138 if (RT_SUCCESS(rc)) 1139 { 1140 pMix->pProps = &pMix->MixBuf.Props; 1141 1142 if (pStream->enmDir == PDMAUDIODIR_IN) 1143 { 1144 rc = AudioMixBufInitPeekState(&pMix->MixBuf, &pMix->PeekState, &pMix->MixBuf.Props); 1145 if (RT_SUCCESS(rc)) 1146 { 1147 rc = AudioMixBufInitWriteState(&pMix->MixBuf, &pMix->WriteState, &pStream->Props); 1148 if (RT_SUCCESS(rc)) 1149 return rc; 1150 } 1151 } 1152 else if (pStream->enmDir == PDMAUDIODIR_OUT) 1153 { 1154 rc = AudioMixBufInitWriteState(&pMix->MixBuf, &pMix->WriteState, &pMix->MixBuf.Props); 1155 if (RT_SUCCESS(rc)) 1156 { 1157 rc = AudioMixBufInitPeekState(&pMix->MixBuf, &pMix->PeekState, &pStream->Props); 1158 if (RT_SUCCESS(rc)) 1159 return rc; 1160 } 1161 } 1162 else 1163 { 1164 RTTestFailed(g_hTest, "Bogus stream direction!"); 1165 rc = VERR_INVALID_STATE; 1166 } 1167 } 1168 else 1169 RTTestFailed(g_hTest, "AudioMixBufInit failed: %Rrc", rc); 1170 RT_ZERO(*pMix); 1171 return rc; 1172 } 1173 1174 1175 /** 1176 * Terminate mixing (leaves the stream untouched). 1177 * 1178 * @param pMix The mixing state. 1179 */ 1180 void AudioTestMixStreamTerm(PAUDIOTESTDRVMIXSTREAM pMix) 1181 { 1182 if (pMix->fDoMixing) 1183 { 1184 AudioMixBufTerm(&pMix->MixBuf); 1185 pMix->pStream = NULL; 1186 } 1187 RT_ZERO(*pMix); 1188 } 1189 1190 1191 /** 1192 * Worker that transports data between the mixer buffer and the drivers. 1193 * 1194 * @returns VBox status code. 1195 * @param pMix The mixer stream setup to do transfers for. 1196 */ 1197 static int audioTestMixStreamTransfer(PAUDIOTESTDRVMIXSTREAM pMix) 1198 { 1199 uint8_t abBuf[16384]; 1200 if (pMix->pStream->enmDir == PDMAUDIODIR_IN) 1201 { 1202 //uint32_t const cbBuf = PDMAudioPropsFloorBytesToFrame(&pMix->pStream->Props, sizeof(abBuf)); 1203 1204 } 1205 else 1206 { 1207 /* 1208 * The goal here is to empty the mixer buffer by transfering all 1209 * the data to the drivers. 1210 */ 1211 uint32_t const cbBuf = PDMAudioPropsFloorBytesToFrame(&pMix->MixBuf.Props, sizeof(abBuf)); 1212 for (;;) 1213 { 1214 uint32_t cFrames = AudioMixBufUsed(&pMix->MixBuf); 1215 if (!cFrames) 1216 break; 1217 1218 uint32_t cbWritable = audioTestDriverStackStreamGetWritable(pMix->pDrvStack, pMix->pStream); 1219 if (!cbWritable) 1220 break; 1221 1222 uint32_t cSrcFramesPeeked; 1223 uint32_t cbDstPeeked; 1224 AudioMixBufPeek(&pMix->MixBuf, 0 /*offSrcFrame*/, cFrames, &cSrcFramesPeeked, 1225 &pMix->PeekState, abBuf, RT_MIN(cbBuf, cbWritable), &cbDstPeeked); 1226 AudioMixBufAdvance(&pMix->MixBuf, cSrcFramesPeeked); 1227 1228 if (!cbDstPeeked) 1229 break; 1230 1231 uint32_t offBuf = 0; 1232 while (offBuf < cbDstPeeked) 1233 { 1234 uint32_t cbPlayed = 0; 1235 int rc = audioTestDriverStackStreamPlay(pMix->pDrvStack, pMix->pStream, 1236 &abBuf[offBuf], cbDstPeeked - offBuf, &cbPlayed); 1237 if (RT_FAILURE(rc)) 1238 return rc; 1239 if (!cbPlayed) 1240 RTThreadSleep(1); 1241 offBuf += cbPlayed; 1242 } 1243 } 1244 } 1245 return VINF_SUCCESS; 1246 } 1247 1248 1249 /** 1250 * Same as audioTestDriverStackStreamDrain. 1251 */ 1252 int AudioTestMixStreamDrain(PAUDIOTESTDRVMIXSTREAM pMix, bool fSync) 1253 { 1254 /* 1255 * If we're mixing, we must first make sure the buffer is empty. 1256 */ 1257 if (pMix->fDoMixing) 1258 { 1259 audioTestMixStreamTransfer(pMix); 1260 while (AudioMixBufUsed(&pMix->MixBuf) > 0) 1261 { 1262 RTThreadSleep(1); 1263 audioTestMixStreamTransfer(pMix); 1264 } 1265 } 1266 1267 /* 1268 * Then we do the regular workt. 1269 */ 1270 return audioTestDriverStackStreamDrain(pMix->pDrvStack, pMix->pStream, fSync); 1271 } 1272 1273 1274 /** 1275 * Same as audioTestDriverStackStreamEnable. 1276 */ 1277 int AudioTestMixStreamEnable(PAUDIOTESTDRVMIXSTREAM pMix) 1278 { 1279 return audioTestDriverStackStreamEnable(pMix->pDrvStack, pMix->pStream); 1280 } 1281 1282 1283 /** 1284 * Same as audioTestDriverStackStreamGetWritable 1285 */ 1286 uint32_t AudioTestMixStreamGetWritable(PAUDIOTESTDRVMIXSTREAM pMix) 1287 { 1288 if (!pMix->fDoMixing) 1289 return audioTestDriverStackStreamGetWritable(pMix->pDrvStack, pMix->pStream); 1290 uint32_t cbRet = AudioMixBufFreeBytes(&pMix->MixBuf); 1291 if (!cbRet) 1292 { 1293 audioTestMixStreamTransfer(pMix); 1294 cbRet = AudioMixBufFreeBytes(&pMix->MixBuf); 1295 } 1296 return cbRet; 1297 } 1298 1299 1300 /** 1301 * Same as audioTestDriverStackStreamIsOkay. 1302 */ 1303 bool AudioTestMixStreamIsOkay(PAUDIOTESTDRVMIXSTREAM pMix) 1304 { 1305 return audioTestDriverStackStreamIsOkay(pMix->pDrvStack, pMix->pStream); 1306 } 1307 1308 1309 /** 1310 * Same as audioTestDriverStackStreamPlay. 1311 */ 1312 int AudioTestMixStreamPlay(PAUDIOTESTDRVMIXSTREAM pMix, void const *pvBuf, uint32_t cbBuf, uint32_t *pcbPlayed) 1313 { 1314 if (!pMix->fDoMixing) 1315 return audioTestDriverStackStreamPlay(pMix->pDrvStack, pMix->pStream, pvBuf, cbBuf, pcbPlayed); 1316 1317 *pcbPlayed = 0; 1318 1319 int rc = audioTestMixStreamTransfer(pMix); 1320 if (RT_FAILURE(rc)) 1321 return rc; 1322 1323 uint32_t const cbFrame = PDMAudioPropsFrameSize(&pMix->MixBuf.Props); 1324 while (cbBuf >= cbFrame) 1325 { 1326 uint32_t const cFrames = AudioMixBufFree(&pMix->MixBuf); 1327 if (!cFrames) 1328 break; 1329 uint32_t cbToWrite = PDMAudioPropsFramesToBytes(&pMix->MixBuf.Props, cFrames); 1330 cbToWrite = RT_MIN(cbToWrite, cbBuf); 1331 cbToWrite = PDMAudioPropsFloorBytesToFrame(&pMix->MixBuf.Props, cbToWrite); 1332 1333 uint32_t cFramesWritten = 0; 1334 AudioMixBufWrite(&pMix->MixBuf, &pMix->WriteState, pvBuf, cbToWrite, 0 /*offDstFrame*/, cFrames, &cFramesWritten); 1335 Assert(cFramesWritten == PDMAudioPropsBytesToFrames(&pMix->MixBuf.Props, cbToWrite)); 1336 AudioMixBufCommit(&pMix->MixBuf, cFramesWritten); 1337 1338 *pcbPlayed += cbToWrite; 1339 cbBuf -= cbToWrite; 1340 pvBuf = (uint8_t const *)pvBuf + cbToWrite; 1341 1342 rc = audioTestMixStreamTransfer(pMix); 1343 if (RT_FAILURE(rc)) 1344 return *pcbPlayed ? VINF_SUCCESS : rc; 1345 } 1346 1347 return VINF_SUCCESS; 1348 } 1349 -
trunk/src/VBox/ValidationKit/utils/audio/vkatInternal.h
r89401 r89439 31 31 #endif 32 32 33 #include "VBoxDD.h" 34 33 #include <VBox/vmm/pdmdrv.h> 35 34 #include <VBox/vmm/pdmaudioinline.h> 36 35 #include <VBox/vmm/pdmaudiohostenuminline.h> 36 #include "Audio/AudioMixBuffer.h" 37 37 38 38 39 /** … … 75 76 typedef AUDIOTESTDRVSTACKSTREAM *PAUDIOTESTDRVSTACKSTREAM; 76 77 77 /** Maximum audio streams a test environment can handle. */ 78 #define AUDIOTESTENV_MAX_STREAMS 8 78 /** 79 * Mixer setup for a stream. 80 */ 81 typedef struct AUDIOTESTDRVMIXSTREAM 82 { 83 /** Pointer to the driver stack. */ 84 PAUDIOTESTDRVSTACK pDrvStack; 85 /** Pointer to the stream. */ 86 PPDMAUDIOSTREAM pStream; 87 /** Properties to use. */ 88 PCPDMAUDIOPCMPROPS pProps; 89 /** Set if we're mixing or just passing thru to the driver stack. */ 90 bool fDoMixing; 91 /** Mixer buffer. */ 92 AUDIOMIXBUF MixBuf; 93 /** Write state. */ 94 AUDIOMIXBUFWRITESTATE WriteState; 95 /** Peek state. */ 96 AUDIOMIXBUFPEEKSTATE PeekState; 97 } AUDIOTESTDRVMIXSTREAM; 98 /** Pointer to mixer setup for a stream. */ 99 typedef AUDIOTESTDRVMIXSTREAM *PAUDIOTESTDRVMIXSTREAM; 100 79 101 80 102 /** The test handle. */ … … 84 106 extern const char *g_pszDrvAudioDebug; 85 107 108 86 109 /** @name Driver stack 87 110 * @{ */ 88 void audioTestDriverStackDelete(PAUDIOTESTDRVSTACK pDrvStack);89 int audioTestDriverStackInit(PAUDIOTESTDRVSTACK pDrvStack, PCPDMDRVREG pDrvReg, bool fWithDrvAudio);90 int audioTestDriverStackSetDevice(PAUDIOTESTDRVSTACK pDrvStack, PDMAUDIODIR enmDir, const char *pszDevId);111 void audioTestDriverStackDelete(PAUDIOTESTDRVSTACK pDrvStack); 112 int audioTestDriverStackInit(PAUDIOTESTDRVSTACK pDrvStack, PCPDMDRVREG pDrvReg, bool fWithDrvAudio); 113 int audioTestDriverStackSetDevice(PAUDIOTESTDRVSTACK pDrvStack, PDMAUDIODIR enmDir, const char *pszDevId); 91 114 /** @} */ 92 115 93 116 /** @name Driver 94 117 * @{ */ 95 int audioTestDrvConstruct(PAUDIOTESTDRVSTACK pDrvStack, PCPDMDRVREG pDrvReg, PPDMDRVINS pParentDrvIns, PPPDMDRVINS ppDrvIns);118 int audioTestDrvConstruct(PAUDIOTESTDRVSTACK pDrvStack, PCPDMDRVREG pDrvReg, PPDMDRVINS pParentDrvIns, PPPDMDRVINS ppDrvIns); 96 119 /** @} */ 97 120 98 121 /** @name Driver stack stream 99 122 * @{ */ 100 int audioTestDriverStackStreamCapture(PAUDIOTESTDRVSTACK pDrvStack, PPDMAUDIOSTREAM pStream, 101 void *pvBuf, uint32_t cbBuf, uint32_t *pcbCaptured); 102 int audioTestDriverStackStreamCreateInput(PAUDIOTESTDRVSTACK pDrvStack, PCPDMAUDIOPCMPROPS pProps, 103 uint32_t cMsBufferSize, uint32_t cMsPreBuffer, uint32_t cMsSchedulingHint, 104 PPDMAUDIOSTREAM *ppStream, PPDMAUDIOSTREAMCFG pCfgAcq); 105 int audioTestDriverStackStreamCreateOutput(PAUDIOTESTDRVSTACK pDrvStack, PCPDMAUDIOPCMPROPS pProps, 106 uint32_t cMsBufferSize, uint32_t cMsPreBuffer, uint32_t cMsSchedulingHint, 107 PPDMAUDIOSTREAM *ppStream, PPDMAUDIOSTREAMCFG pCfgAcq); 108 void audioTestDriverStackStreamDestroy(PAUDIOTESTDRVSTACK pDrvStack, PPDMAUDIOSTREAM pStream); 109 int audioTestDriverStackStreamDrain(PAUDIOTESTDRVSTACK pDrvStack, PPDMAUDIOSTREAM pStream, bool fSync); 110 int audioTestDriverStackStreamEnable(PAUDIOTESTDRVSTACK pDrvStack, PPDMAUDIOSTREAM pStream); 111 uint32_t audioTestDriverStackStreamGetWritable(PAUDIOTESTDRVSTACK pDrvStack, PPDMAUDIOSTREAM pStream); 112 bool audioTestDriverStackStreamIsOkay(PAUDIOTESTDRVSTACK pDrvStack, PPDMAUDIOSTREAM pStream); 113 int audioTestDriverStackStreamPlay(PAUDIOTESTDRVSTACK pDrvStack, PPDMAUDIOSTREAM pStream, void const *pvBuf, uint32_t cbBuf, uint32_t *pcbPlayed); 123 int audioTestDriverStackStreamCreateInput(PAUDIOTESTDRVSTACK pDrvStack, PCPDMAUDIOPCMPROPS pProps, 124 uint32_t cMsBufferSize, uint32_t cMsPreBuffer, uint32_t cMsSchedulingHint, 125 PPDMAUDIOSTREAM *ppStream, PPDMAUDIOSTREAMCFG pCfgAcq); 126 int audioTestDriverStackStreamCreateOutput(PAUDIOTESTDRVSTACK pDrvStack, PCPDMAUDIOPCMPROPS pProps, 127 uint32_t cMsBufferSize, uint32_t cMsPreBuffer, uint32_t cMsSchedulingHint, 128 PPDMAUDIOSTREAM *ppStream, PPDMAUDIOSTREAMCFG pCfgAcq); 129 void audioTestDriverStackStreamDestroy(PAUDIOTESTDRVSTACK pDrvStack, PPDMAUDIOSTREAM pStream); 130 int audioTestDriverStackStreamDrain(PAUDIOTESTDRVSTACK pDrvStack, PPDMAUDIOSTREAM pStream, bool fSync); 131 int audioTestDriverStackStreamEnable(PAUDIOTESTDRVSTACK pDrvStack, PPDMAUDIOSTREAM pStream); 132 int audioTestDriverStackStreamDisable(PAUDIOTESTDRVSTACK pDrvStack, PPDMAUDIOSTREAM pStream); 133 uint32_t audioTestDriverStackStreamGetWritable(PAUDIOTESTDRVSTACK pDrvStack, PPDMAUDIOSTREAM pStream); 134 bool audioTestDriverStackStreamIsOkay(PAUDIOTESTDRVSTACK pDrvStack, PPDMAUDIOSTREAM pStream); 135 int audioTestDriverStackStreamPlay(PAUDIOTESTDRVSTACK pDrvStack, PPDMAUDIOSTREAM pStream, void const *pvBuf, 136 uint32_t cbBuf, uint32_t *pcbPlayed); 137 int audioTestDriverStackStreamCapture(PAUDIOTESTDRVSTACK pDrvStack, PPDMAUDIOSTREAM pStream, 138 void *pvBuf, uint32_t cbBuf, uint32_t *pcbCaptured); 114 139 /** @} */ 140 141 142 /** @name Mixing stream 143 * @{ */ 144 int AudioTestMixStreamInit(PAUDIOTESTDRVMIXSTREAM pMix, PAUDIOTESTDRVSTACK pDrvStack, PPDMAUDIOSTREAM pStream, 145 PCPDMAUDIOPCMPROPS pProps, uint32_t cMsBuffer); 146 void AudioTestMixStreamTerm(PAUDIOTESTDRVMIXSTREAM pMix); 147 int AudioTestMixStreamDrain(PAUDIOTESTDRVMIXSTREAM pMix, bool fSync); 148 int AudioTestMixStreamEnable(PAUDIOTESTDRVMIXSTREAM pMix); 149 uint32_t AudioTestMixStreamGetWritable(PAUDIOTESTDRVMIXSTREAM pMix); 150 bool AudioTestMixStreamIsOkay(PAUDIOTESTDRVMIXSTREAM pMix); 151 int AudioTestMixStreamPlay(PAUDIOTESTDRVMIXSTREAM pMix, void const *pvBuf, uint32_t cbBuf, uint32_t *pcbPlayed); 152 int AudioTestMixStreamCapture(PAUDIOTESTDRVMIXSTREAM pMix, void *pvBuf, uint32_t cbBuf, uint32_t *pcbCaptured); 153 /** @} */ 154 115 155 116 156 #endif /* !VBOX_INCLUDED_SRC_audio_vkatInternal_h */
Note:
See TracChangeset
for help on using the changeset viewer.