Changeset 88645 in vbox for trunk/src/VBox/Devices/Audio
- Timestamp:
- Apr 22, 2021 8:32:12 AM (4 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Audio/DevSB16.cpp
r88561 r88645 95 95 typedef struct SB16DRIVERSTREAM 96 96 { 97 /** Associated PDM audio stream. */98 R3PTRTYPE(P PDMAUDIOSTREAM) pStream;97 /** Associated mixer stream handle. */ 98 R3PTRTYPE(PAUDMIXSTREAM) pMixStrm; 99 99 /** The stream's current configuration. */ 100 100 } SB16DRIVERSTREAM, *PSB16DRIVERSTREAM; … … 206 206 /** The base interface for LUN\#0. */ 207 207 PDMIBASE IBase; 208 208 209 /** Output stream. */ 209 SB16STREAM Out; 210 SB16STREAM StreamOut; 211 /** The device's software mixer. */ 212 R3PTRTYPE(PAUDIOMIXER) pMixer; 213 /** Audio sink for PCM output. */ 214 R3PTRTYPE(PAUDMIXSINK) pSinkOut; 210 215 211 216 /** The timer for pumping data thru the attached LUN drivers. */ … … 232 237 } SB16STATE; 233 238 234 235 239 /********************************************************************************************************************************* 236 240 * Internal Functions * 237 241 *********************************************************************************************************************************/ 238 242 static int sb16CheckAndReOpenOut(PPDMDEVINS pDevIns, PSB16STATE pThis); 239 static int sb16 OpenOut(PPDMDEVINS pDevIns, PSB16STATE pThis, PPDMAUDIOSTREAMCFG pCfg);240 static void sb16 CloseOut(PSB16STATE pThis);243 static int sb16StreamOpen(PPDMDEVINS pDevIns, PSB16STATE pThis, PSB16STREAM pStream, PPDMAUDIOSTREAMCFG pCfg); 244 static void sb16StreamClose(PPDMDEVINS pDevIns, PSB16STATE pThis, PSB16STREAM pStream); 241 245 static void sb16TimerMaybeStart(PPDMDEVINS pDevIns, PSB16STATE pThis); 242 246 static void sb16TimerMaybeStop(PSB16STATE pThis); … … 273 277 PDMDevHlpDMASetDREQ(pThis->pDevInsR3, dma, hold); 274 278 275 PSB16DRIVER pDrv; 276 RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node) 277 { 278 if (!pDrv->Out.pStream) 279 continue; 280 281 int rc2 = pDrv->pConnector->pfnStreamControl(pDrv->pConnector, pDrv->Out.pStream, 282 hold == 1 ? PDMAUDIOSTREAMCMD_ENABLE : PDMAUDIOSTREAMCMD_DISABLE); 283 LogFlowFunc(("%s: rc=%Rrc\n", pDrv->Out.pStream->szName, rc2)); NOREF(rc2); 284 } 279 int rc2 = AudioMixerSinkCtl(pThis->pSinkOut, 280 hold == 1 ? AUDMIXSINKCMD_ENABLE : AUDMIXSINKCMD_DISABLE); 281 AssertRC(rc2); 285 282 286 283 if (hold) … … 895 892 } 896 893 897 static void sb16CmdResetLegacy(P SB16STATE pThis)894 static void sb16CmdResetLegacy(PPDMDEVINS pDevIns, PSB16STATE pThis) 898 895 { 899 896 LogFlowFuncEnter(); … … 905 902 906 903 /* At the moment we only have one stream, the output stream. */ 907 PPDMAUDIOSTREAMCFG pCfg = &pThis->Out.Cfg; 908 909 pCfg->enmDir = PDMAUDIODIR_OUT; 910 pCfg->u.enmDst = PDMAUDIOPLAYBACKDST_FRONT; 911 pCfg->enmLayout = PDMAUDIOSTREAMLAYOUT_NON_INTERLEAVED; 912 PDMAudioPropsInit(&pCfg->Props, 1 /*8-bit*/, false /*fSigned*/, 1 /*mono*/, pThis->freq); 913 914 AssertCompile(sizeof(pCfg->szName) >= sizeof("Output")); 915 memcpy(pCfg->szName, "Output", sizeof("Output")); 916 917 sb16CloseOut(pThis); 904 PSB16STREAM pStream = &pThis->StreamOut; 905 906 pStream->Cfg.enmDir = PDMAUDIODIR_OUT; 907 pStream->Cfg.u.enmDst = PDMAUDIOPLAYBACKDST_FRONT; 908 pStream->Cfg.enmLayout = PDMAUDIOSTREAMLAYOUT_NON_INTERLEAVED; 909 910 PDMAudioPropsInit(&pStream->Cfg.Props, 1 /* 8-bit */, false /* fSigned */, 1 /* Mono */, pThis->freq); 911 RTStrCopy(pStream->Cfg.szName, sizeof(pStream->Cfg.szName), "Output"); 912 913 sb16StreamClose(pDevIns, pThis, pStream); 918 914 } 919 915 … … 943 939 944 940 sb16Control(pDevIns, pThis, 0); 945 sb16CmdResetLegacy(p This);941 sb16CmdResetLegacy(pDevIns, pThis); 946 942 } 947 943 … … 1192 1188 } 1193 1189 1194 PSB16DRIVER pDrv; 1195 RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node) 1196 { 1197 PPDMAUDIOSTREAM pStream = pDrv->Out.pStream; 1198 if (pStream) 1199 { 1200 int rc2 = pDrv->pConnector->pfnStreamSetVolume(pDrv->pConnector, pStream, &VolCombined); 1201 AssertRC(rc2); 1202 } 1203 } 1190 int rc2 = AudioMixerSinkSetVolume(pThis->pSinkOut, &VolCombined); 1191 AssertRC(rc2); 1204 1192 } 1205 1193 … … 1517 1505 * Worker for sb16DMARead. 1518 1506 */ 1519 static int sb16WriteAudio(PSB16STATE pThis, int nchan, uint32_t dma_pos, uint32_t dma_len, int len) 1520 { 1521 uint8_t abBuf[_4K]; /** @todo Have a buffer on the heap. */ 1522 uint32_t cbToWrite = len; 1507 static int sb16WriteAudio(PSB16STATE pThis, int nchan, uint32_t dma_pos, uint32_t dma_len, uint32_t len, uint32_t *pcbWritten) 1508 { 1509 uint8_t abBuf[_4K]; /** @todo Have a buffer on the heap. */ 1510 1511 uint32_t cbToWrite = len; 1523 1512 uint32_t cbWrittenTotal = 0; 1524 1513 1514 PAUDMIXSINK pDstMixSink = pThis->pSinkOut; 1515 AssertPtrReturn(pDstMixSink, VERR_INVALID_POINTER); 1516 1517 int rc = VINF_SUCCESS; 1518 1525 1519 while (cbToWrite) 1526 1520 { 1527 1521 uint32_t cbToRead = RT_MIN(dma_len - dma_pos, cbToWrite); 1528 if (cbToRead > sizeof(abBuf))1529 cbToRead = sizeof(abBuf);1522 if (cbToRead > (int)sizeof(abBuf)) /** @todo BUGBUG Clean this up. */ 1523 cbToRead = (int)sizeof(abBuf); 1530 1524 1531 1525 uint32_t cbRead = 0; 1532 int rc2= PDMDevHlpDMAReadMemory(pThis->pDevInsR3, nchan, abBuf, dma_pos, cbToRead, &cbRead);1533 AssertMsgRC (rc2, (" from DMA failed: %Rrc\n", rc2));1526 rc = PDMDevHlpDMAReadMemory(pThis->pDevInsR3, nchan, abBuf, dma_pos, cbToRead, &cbRead); 1527 AssertMsgRCReturn(rc, ("Reading from DMA failed, rc=%Rrc\n", rc), rc); 1534 1528 1535 1529 #ifdef VBOX_AUDIO_DEBUG_DUMP_PCM_DATA … … 1547 1541 */ 1548 1542 uint32_t cbWritten = 0; 1549 1550 /* Just multiplex the output to the connected backends. 1551 * No need to utilize the virtual mixer here (yet). */ 1552 PSB16DRIVER pDrv; 1553 RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node) 1554 { 1555 if ( pDrv->Out.pStream 1556 && PDMAudioStrmStatusCanWrite(pDrv->pConnector->pfnStreamGetStatus(pDrv->pConnector, pDrv->Out.pStream))) 1557 { 1558 uint32_t cbWrittenToStream = 0; 1559 rc2 = pDrv->pConnector->pfnStreamWrite(pDrv->pConnector, pDrv->Out.pStream, abBuf, cbRead, &cbWrittenToStream); 1560 1561 LogFlowFunc(("\tLUN#%RU8: rc=%Rrc, cbWrittenToStream=%RU32\n", pDrv->uLUN, rc2, cbWrittenToStream)); 1562 } 1563 } 1564 1565 cbWritten = cbRead; /* Always report everything written, as the backends need to keep up themselves. */ 1566 1567 LogFlowFunc(("\tcbToRead=%RU32, cbToWrite=%RU32, cbWritten=%RU32, cbLeft=%RU32\n", 1568 cbToRead, cbToWrite, cbWritten, cbToWrite - cbWrittenTotal)); 1569 1570 if (!cbWritten) 1543 rc = AudioMixerSinkWrite(pDstMixSink, AUDMIXOP_COPY, abBuf, cbRead, &cbWritten); 1544 if ( !cbWritten /* Nothing written? */ 1545 || RT_FAILURE(rc)) 1571 1546 break; 1572 1547 … … 1577 1552 } 1578 1553 1579 return cbWrittenTotal; 1554 if (pcbWritten) 1555 *pcbWritten = cbWrittenTotal; 1556 1557 return rc; 1580 1558 } 1581 1559 … … 1589 1567 RT_NOREF(pDevIns); 1590 1568 PSB16STATE pThis = (PSB16STATE)pvUser; 1591 int till, copy, written,free;1569 int till, copy, free; 1592 1570 1593 1571 if (pThis->block_size <= 0) … … 1622 1600 } 1623 1601 1624 written = sb16WriteAudio(pThis, uChannel, off, cb, copy); 1625 off = (off + written) % cb; 1626 pThis->left_till_irq -= written; 1602 uint32_t cbWritten; 1603 int rc = sb16WriteAudio(pThis, uChannel, off, cb, copy, &cbWritten); 1604 AssertRC(rc); 1605 1606 /** @todo Convert the rest to uin32_t / size_t. */ 1607 off = (off + (int)cbWritten) % cb; 1608 pThis->left_till_irq -= (int)cbWritten; 1627 1609 1628 1610 if (pThis->left_till_irq <= 0) … … 1637 1619 } 1638 1620 1639 Log3Func(("pos %d/%d free %5d till %5d copy %5d written %5d block_size%5d\n",1640 off, cb, free, pThis->left_till_irq, copy, written, pThis->block_size));1621 Log3Func(("pos %d/%d, free=%5d, till=%5d, copy=%5d, written=%RU32, block_size=%5d\n", 1622 off, cb, free, pThis->left_till_irq, copy, cbWritten, pThis->block_size)); 1641 1623 1642 1624 while (pThis->left_till_irq <= 0) … … 1691 1673 1692 1674 uint64_t cTicksNow = PDMDevHlpTimerGet(pDevIns, hTimer); 1693 bool fIsPlaying = false; /* Whether one or more streams are still playing. */1694 bool fDoTransfer = false;1695 1675 1696 1676 pThis->tsTimerIO = cTicksNow; 1697 1677 1698 PSB16DRIVER pDrv; 1699 RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node) 1700 { 1701 PPDMAUDIOSTREAM const pStream = pDrv->Out.pStream; 1702 PPDMIAUDIOCONNECTOR const pConn = pDrv->pConnector; 1703 if (pStream && pConn) 1704 { 1705 int rc2 = pConn->pfnStreamIterate(pConn, pStream); 1706 if (RT_SUCCESS(rc2)) 1707 { 1708 rc2 = pConn->pfnStreamPlay(pConn, pStream, NULL /* cPlayed */); 1709 if (RT_FAILURE(rc2)) 1710 { 1711 LogFlowFunc(("%s: Failed playing stream, rc=%Rrc\n", pStream->szName, rc2)); 1712 continue; 1713 } 1714 1715 /* Only do the next DMA transfer if we're able to write the remaining data block. */ 1716 fDoTransfer = pConn->pfnStreamGetWritable(pConn, pStream) > (unsigned)pThis->left_till_irq; 1717 } 1718 1719 PDMAUDIOSTREAMSTS fStrmSts = pConn->pfnStreamGetStatus(pConn, pStream); 1720 fIsPlaying |= RT_BOOL(fStrmSts & (PDMAUDIOSTREAMSTS_FLAGS_ENABLED | PDMAUDIOSTREAMSTS_FLAGS_PENDING_DISABLE)); 1721 } 1722 } 1678 int rc2 = AudioMixerSinkUpdate(pThis->pSinkOut); 1679 AssertRC(rc2); 1723 1680 1724 1681 bool fTimerActive = ASMAtomicReadBool(&pThis->fTimerActive); 1725 bool fArmTimer = fTimerActive || fIsPlaying; 1726 LogFlowFunc(("fTimerActive=%RTbool, fIsPlaying=%RTbool\n", fTimerActive, fIsPlaying)); 1727 1728 if (fDoTransfer) 1729 { 1730 /* Schedule the next transfer. */ 1731 PDMDevHlpDMASchedule(pDevIns); 1732 1733 /* Arm the timer at least one more time. */ 1734 fArmTimer = true; 1735 } 1682 bool fArmTimer = fTimerActive; 1683 1684 /* Schedule the next transfer. */ 1685 PDMDevHlpDMASchedule(pDevIns); 1686 1687 /* Arm the timer at least one more time. */ 1688 fArmTimer = true; 1736 1689 1737 1690 /* … … 1753 1706 1754 1707 /** 1755 * Creates the output PDM audio stream for a specific driver. 1708 * Retrieves a specific driver stream of a SB16 driver. 1709 * 1710 * @returns Pointer to driver stream if found, or NULL if not found. 1711 * @param pDrv Driver to retrieve driver stream for. 1712 * @param enmDir Stream direction to retrieve. 1713 * @param dstSrc Stream destination / source to retrieve. 1714 */ 1715 static PSB16DRIVERSTREAM sb16GetDrvStream(PSB16DRIVER pDrv, PDMAUDIODIR enmDir, PDMAUDIODSTSRCUNION dstSrc) 1716 { 1717 PSB16DRIVERSTREAM pDrvStream = NULL; 1718 1719 if (enmDir == PDMAUDIODIR_IN) 1720 { 1721 return NULL; /** @todo Recording not implemented yet. */ 1722 } 1723 else if (enmDir == PDMAUDIODIR_OUT) 1724 { 1725 LogFunc(("enmDst=%RU32\n", dstSrc.enmDst)); 1726 1727 switch (dstSrc.enmDst) 1728 { 1729 case PDMAUDIOPLAYBACKDST_FRONT: 1730 pDrvStream = &pDrv->Out; 1731 break; 1732 default: 1733 AssertFailed(); 1734 break; 1735 } 1736 } 1737 else 1738 AssertFailed(); 1739 1740 return pDrvStream; 1741 } 1742 1743 /** 1744 * Adds a driver stream to a specific mixer sink. 1756 1745 * 1757 1746 * @returns VBox status code. 1758 * @param pCfg Stream configuration to use. 1759 * @param pDrv Driver stream to create PDM stream for. 1760 */ 1761 static int sb16CreateDrvStream(PPDMAUDIOSTREAMCFG pCfg, PSB16DRIVER pDrv) 1762 { 1763 AssertReturn(pCfg->enmDir == PDMAUDIODIR_OUT, VERR_INVALID_PARAMETER); 1764 Assert(AudioHlpStreamCfgIsValid(pCfg)); 1765 1766 PPDMAUDIOSTREAMCFG pCfgHost = PDMAudioStrmCfgDup(pCfg); 1767 if (!pCfgHost) 1747 * @param pDevIns The device instance. 1748 * @param pMixSink Mixer sink to add driver stream to. 1749 * @param pCfg Stream configuration to use. 1750 * @param pDrv Driver stream to add. 1751 */ 1752 static int sb16AddDrvStream(PPDMDEVINS pDevIns, PAUDMIXSINK pMixSink, PPDMAUDIOSTREAMCFG pCfg, PSB16DRIVER pDrv) 1753 { 1754 AssertReturn(pCfg->enmDir == PDMAUDIODIR_OUT, VERR_NOT_IMPLEMENTED); /* We don't support recording for SB16 so far. */ 1755 1756 PPDMAUDIOSTREAMCFG pStreamCfg = PDMAudioStrmCfgDup(pCfg); 1757 if (!pStreamCfg) 1768 1758 return VERR_NO_MEMORY; 1769 1759 1770 LogFunc(("[LUN#%RU8] %s\n", pDrv->uLUN, pCfgHost->szName)); 1771 1772 AssertMsg(pDrv->Out.pStream == NULL, ("[LUN#%RU8] Driver stream already present when it must not\n", pDrv->uLUN)); 1773 1774 /* Disable pre-buffering for SB16; not needed for that bit of data. */ 1775 pCfgHost->Backend.cFramesPreBuffering = 0; 1776 1777 int rc = pDrv->pConnector->pfnStreamCreate(pDrv->pConnector, 0 /*fFlags*/, pCfgHost, pCfg /* pCfgGuest */, &pDrv->Out.pStream); 1778 if (RT_SUCCESS(rc)) 1779 { 1780 pDrv->pConnector->pfnStreamRetain(pDrv->pConnector, pDrv->Out.pStream); 1781 LogFlowFunc(("LUN#%RU8: Created output \"%s\", rc=%Rrc\n", pDrv->uLUN, pCfg->szName, rc)); 1782 } 1783 1784 PDMAudioStrmCfgFree(pCfgHost); 1785 1760 if (!RTStrPrintf(pStreamCfg->szName, sizeof(pStreamCfg->szName), "%s", pCfg->szName)) 1761 { 1762 PDMAudioStrmCfgFree(pStreamCfg); 1763 return VERR_BUFFER_OVERFLOW; 1764 } 1765 1766 LogFunc(("[LUN#%RU8] %s\n", pDrv->uLUN, pStreamCfg->szName)); 1767 1768 int rc; 1769 1770 PSB16DRIVERSTREAM pDrvStream = sb16GetDrvStream(pDrv, pStreamCfg->enmDir, pStreamCfg->u); 1771 if (pDrvStream) 1772 { 1773 AssertMsg(pDrvStream->pMixStrm == NULL, ("[LUN#%RU8] Driver stream already present when it must not\n", pDrv->uLUN)); 1774 1775 PAUDMIXSTREAM pMixStrm; 1776 rc = AudioMixerSinkCreateStream(pMixSink, pDrv->pConnector, pStreamCfg, 0 /* fFlags */, pDevIns, &pMixStrm); 1777 LogFlowFunc(("LUN#%RU8: Created stream \"%s\" for sink, rc=%Rrc\n", pDrv->uLUN, pStreamCfg->szName, rc)); 1778 if (RT_SUCCESS(rc)) 1779 { 1780 rc = AudioMixerSinkAddStream(pMixSink, pMixStrm); 1781 LogFlowFunc(("LUN#%RU8: Added stream \"%s\" to sink, rc=%Rrc\n", pDrv->uLUN, pStreamCfg->szName, rc)); 1782 1783 if (RT_SUCCESS(rc)) 1784 { 1785 pDrvStream->pMixStrm = pMixStrm; 1786 } 1787 else 1788 AudioMixerStreamDestroy(pMixStrm, pDevIns); 1789 } 1790 } 1791 else 1792 rc = VERR_INVALID_PARAMETER; 1793 1794 PDMAudioStrmCfgFree(pStreamCfg); 1795 1796 LogFlowFuncLeaveRC(rc); 1786 1797 return rc; 1787 1798 } 1788 1799 1789 1800 /** 1790 * Destroys the output PDM audio stream of a specific driver.1801 * Adds all current driver streams to a specific mixer sink. 1791 1802 * 1792 * @param pDrv Driver stream to destroy PDM stream for. 1793 */ 1794 static void sb16DestroyDrvStreamOut(PSB16DRIVER pDrv) 1795 { 1796 AssertPtr(pDrv); 1797 1798 if (pDrv->Out.pStream) 1799 { 1800 pDrv->pConnector->pfnStreamRelease(pDrv->pConnector, pDrv->Out.pStream); 1801 1802 int rc2 = pDrv->pConnector->pfnStreamControl(pDrv->pConnector, pDrv->Out.pStream, PDMAUDIOSTREAMCMD_DISABLE); 1803 AssertRC(rc2); 1804 1805 rc2 = pDrv->pConnector->pfnStreamDestroy(pDrv->pConnector, pDrv->Out.pStream); 1806 AssertRC(rc2); 1807 1808 pDrv->Out.pStream = NULL; 1809 } 1803 * @returns VBox status code. 1804 * @param pDevIns The device instance. 1805 * @param pThis The SB16 state. 1806 * @param pMixSink Mixer sink to add stream to. 1807 * @param pCfg Stream configuration to use. 1808 */ 1809 static int sb16AddDrvStreams(PPDMDEVINS pDevIns, PSB16STATE pThis, PAUDMIXSINK pMixSink, PPDMAUDIOSTREAMCFG pCfg) 1810 { 1811 AssertPtrReturn(pMixSink, VERR_INVALID_POINTER); 1812 1813 if (!AudioHlpStreamCfgIsValid(pCfg)) 1814 return VERR_INVALID_PARAMETER; 1815 1816 int rc = AudioMixerSinkSetFormat(pMixSink, &pCfg->Props); 1817 if (RT_FAILURE(rc)) 1818 return rc; 1819 1820 PSB16DRIVER pDrv; 1821 RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node) 1822 { 1823 int rc2 = sb16AddDrvStream(pDevIns, pMixSink, pCfg, pDrv); 1824 if (RT_FAILURE(rc2)) 1825 LogFunc(("Attaching stream failed with %Rrc\n", rc2)); 1826 1827 /* Do not pass failure to rc here, as there might be drivers which aren't 1828 * configured / ready yet. */ 1829 } 1830 1831 LogFlowFuncLeaveRC(rc); 1832 return rc; 1833 } 1834 1835 /** 1836 * Removes a driver stream from a specific mixer sink. 1837 * 1838 * @param pDevIns The device instance. 1839 * @param pMixSink Mixer sink to remove audio streams from. 1840 * @param enmDir Stream direction to remove. 1841 * @param dstSrc Stream destination / source to remove. 1842 * @param pDrv Driver stream to remove. 1843 */ 1844 static void sb16RemoveDrvStream(PPDMDEVINS pDevIns, PAUDMIXSINK pMixSink, PDMAUDIODIR enmDir, 1845 PDMAUDIODSTSRCUNION dstSrc, PSB16DRIVER pDrv) 1846 { 1847 PSB16DRIVERSTREAM pDrvStream = sb16GetDrvStream(pDrv, enmDir, dstSrc); 1848 if (pDrvStream) 1849 { 1850 if (pDrvStream->pMixStrm) 1851 { 1852 LogFlowFunc(("[LUN#%RU8]\n", pDrv)); 1853 1854 AudioMixerSinkRemoveStream(pMixSink, pDrvStream->pMixStrm); 1855 1856 AudioMixerStreamDestroy(pDrvStream->pMixStrm, pDevIns); 1857 pDrvStream->pMixStrm = NULL; 1858 } 1859 } 1860 } 1861 1862 /** 1863 * Removes all driver streams from a specific mixer sink. 1864 * 1865 * @param pDevIns The device instance. 1866 * @param pThisCC The SB16 state. 1867 * @param pMixSink Mixer sink to remove audio streams from. 1868 * @param enmDir Stream direction to remove. 1869 * @param dstSrc Stream destination / source to remove. 1870 */ 1871 static void sb16RemoveDrvStreams(PPDMDEVINS pDevIns, PSB16STATE pThis, PAUDMIXSINK pMixSink, 1872 PDMAUDIODIR enmDir, PDMAUDIODSTSRCUNION dstSrc) 1873 { 1874 AssertPtrReturnVoid(pMixSink); 1875 1876 PSB16DRIVER pDrv; 1877 RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node) 1878 sb16RemoveDrvStream(pDevIns, pMixSink, enmDir, dstSrc, pDrv); 1879 } 1880 1881 /** 1882 * Adds a specific SB16 driver to the driver chain. 1883 * 1884 * @returns VBox status code. 1885 * @param pDevIns The device instance. 1886 * @param pThis The SB16 device state. 1887 * @param pDrv The SB16 driver to add. 1888 */ 1889 static int sb16AddDrv(PPDMDEVINS pDevIns, PSB16STATE pThis, PSB16DRIVER pDrv) 1890 { 1891 int rc = VINF_SUCCESS; 1892 1893 if (AudioHlpStreamCfgIsValid(&pThis->StreamOut.Cfg)) 1894 rc = sb16AddDrvStream(pDevIns, pThis->pSinkOut, &pThis->StreamOut.Cfg, pDrv); 1895 1896 return rc; 1897 } 1898 1899 /** 1900 * Removes a specific SB16 driver from the driver chain and destroys its 1901 * associated streams. 1902 * 1903 * @param pDevIns The device instance. 1904 * @param pThis The SB16 device state. 1905 * @param pDrv SB16 driver to remove. 1906 */ 1907 static void sb16RemoveDrv(PPDMDEVINS pDevIns, PSB16STATE pThis, PSB16DRIVER pDrv) 1908 { 1909 RT_NOREF(pDevIns); 1910 1911 /** @todo We only implement one single output (playback) stream at the moment. */ 1912 1913 if (pDrv->Out.pMixStrm) 1914 { 1915 AudioMixerSinkRemoveStream(pThis->pSinkOut, pDrv->Out.pMixStrm); 1916 AudioMixerStreamDestroy(pDrv->Out.pMixStrm, pDevIns); 1917 pDrv->Out.pMixStrm = NULL; 1918 } 1919 1920 RTListNodeRemove(&pDrv->Node); 1810 1921 } 1811 1922 … … 1823 1934 int rc = VINF_SUCCESS; 1824 1935 1936 PSB16STREAM pStream = &pThis->StreamOut; 1937 1825 1938 if (pThis->freq > 0) 1826 1939 { … … 1830 1943 PDMAudioPropsInit(&Cfg.Props, pThis->fmt_bits / 8, pThis->fmt_signed != 0, 1 << pThis->fmt_stereo, pThis->freq); 1831 1944 1832 if (!PDMAudioStrmCfgMatchesProps(&Cfg, &p This->Out.Cfg.Props))1945 if (!PDMAudioStrmCfgMatchesProps(&Cfg, &pStream->Cfg.Props)) 1833 1946 { 1834 1947 Cfg.enmDir = PDMAUDIODIR_OUT; … … 1836 1949 Cfg.enmLayout = PDMAUDIOSTREAMLAYOUT_NON_INTERLEAVED; 1837 1950 1838 strcpy(Cfg.szName, "Output");1839 1840 sb16 CloseOut(pThis);1841 1842 rc = sb16 OpenOut(pDevIns, pThis, &Cfg);1951 RTStrCopy(Cfg.szName, sizeof(Cfg.szName), "Output"); 1952 1953 sb16StreamClose(pDevIns, pThis, pStream); 1954 1955 rc = sb16StreamOpen(pDevIns, pThis, pStream, &Cfg); 1843 1956 AssertRC(rc); 1844 1957 } 1845 1958 } 1846 1959 else 1847 sb16 CloseOut(pThis);1960 sb16StreamClose(pDevIns, pThis, pStream); 1848 1961 1849 1962 LogFlowFuncLeaveRC(rc); … … 1851 1964 } 1852 1965 1853 static int sb16OpenOut(PPDMDEVINS pDevIns, PSB16STATE pThis, PPDMAUDIOSTREAMCFG pCfg) 1966 /** 1967 * Opens a SB16 stream with its current mixer settings. 1968 * 1969 * @returns VBox status code. 1970 * @param pDevIns The device instance. 1971 * @param pThis The SB16 device state. 1972 * @param pStream The SB16 stream to open. 1973 * @param pCfg Stream configuration to use for opening the stream. 1974 * 1975 * @note This currently only supports the one and only output stream. 1976 */ 1977 static int sb16StreamOpen(PPDMDEVINS pDevIns, PSB16STATE pThis, PSB16STREAM pStream, PPDMAUDIOSTREAMCFG pCfg) 1854 1978 { 1855 1979 LogFlowFuncEnter(); 1856 AssertPtr(pThis);1857 AssertPtr(pCfg);1858 1980 1859 1981 if (!AudioHlpStreamCfgIsValid(pCfg)) 1860 1982 return VERR_INVALID_PARAMETER; 1861 1983 1862 int rc = PDMAudioStrmCfgCopy(&pThis->Out.Cfg, pCfg); 1984 /** @todo Implement mixer sink selection (and it's in/out + destination mapping) here once we add more streams. */ 1985 PAUDMIXSINK pMixerSink = pThis->pSinkOut; 1986 AssertPtr(pMixerSink); 1987 1988 PDMAUDIODSTSRCUNION dstSrc; 1989 dstSrc.enmDst = PDMAUDIOPLAYBACKDST_FRONT; 1990 1991 PDMAUDIODIR enmDir = PDMAUDIODIR_OUT; 1992 1993 int rc = PDMAudioStrmCfgCopy(&pStream->Cfg, pCfg); 1863 1994 if (RT_SUCCESS(rc)) 1864 1995 { 1865 1996 /* Set scheduling hint (if available). */ 1866 1997 if (pThis->cTicksTimerIOInterval) 1867 pThis->Out.Cfg.Device.cMsSchedulingHint = 1000 /* ms */ 1868 / ( PDMDevHlpTimerGetFreq(pDevIns, pThis->hTimerIO) 1869 / RT_MIN(pThis->cTicksTimerIOInterval, 1)); 1870 1871 PSB16DRIVER pDrv; 1872 RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node) 1873 { 1874 int rc2 = sb16CreateDrvStream(&pThis->Out.Cfg, pDrv); 1875 if (RT_FAILURE(rc2)) 1876 LogFunc(("Attaching stream failed with %Rrc\n", rc2)); 1877 1878 /* Do not pass failure to rc here, as there might be drivers which aren't 1879 * configured / ready yet. */ 1880 } 1881 1882 sb16UpdateVolume(pThis); 1998 pStream->Cfg.Device.cMsSchedulingHint = 1000 /* ms */ 1999 / ( PDMDevHlpTimerGetFreq(pDevIns, pThis->hTimerIO) 2000 / RT_MIN(pThis->cTicksTimerIOInterval, 1)); 2001 2002 sb16RemoveDrvStreams(pDevIns, pThis, pMixerSink, enmDir, dstSrc); 2003 2004 rc = sb16AddDrvStreams(pDevIns, pThis, pMixerSink, &pStream->Cfg); 2005 if (RT_SUCCESS(rc)) 2006 sb16UpdateVolume(pThis); 1883 2007 } 1884 2008 … … 1887 2011 } 1888 2012 1889 static void sb16CloseOut(PSB16STATE pThis) 2013 /** 2014 * Closes a SB16 stream. 2015 * 2016 * @param pDevIns The device instance. 2017 * @param pThis SB16 state. 2018 * @param pStream The SB16 stream to close. 2019 */ 2020 static void sb16StreamClose(PPDMDEVINS pDevIns, PSB16STATE pThis, PSB16STREAM pStream) 1890 2021 { 1891 2022 LogFlowFuncEnter(); 1892 AssertPtr(pThis); 1893 1894 PSB16DRIVER pDrv; 1895 RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node) 1896 { 1897 sb16DestroyDrvStreamOut(pDrv); 1898 } 2023 2024 /** @todo Implement mixer sink selection (and it's in/out + destination mapping) here once we add more streams. */ 2025 RT_NOREF(pStream); 2026 PAUDMIXSINK pMixerSink = pThis->pSinkOut; 2027 AssertPtr(pMixerSink); 2028 2029 PDMAUDIODSTSRCUNION dstSrc; 2030 dstSrc.enmDst = PDMAUDIOPLAYBACKDST_FRONT; 2031 2032 PDMAUDIODIR enmDir = PDMAUDIODIR_OUT; 2033 2034 sb16RemoveDrvStreams(pDevIns, pThis, pMixerSink, enmDir, dstSrc); 1899 2035 1900 2036 LogFlowFuncLeave(); … … 2200 2336 * 2201 2337 * @returns VBox status code. 2202 * @param pDrv Driver to detach device from. 2203 */ 2204 static int sb16DetachInternal(PSB16DRIVER pDrv) 2205 { 2206 sb16DestroyDrvStreamOut(pDrv); 2207 RTListNodeRemove(&pDrv->Node); 2208 LogFunc(("uLUN=%u\n", pDrv->uLUN)); 2338 * @param pDevIns The device instance. 2339 * @param pThis The SB16 device state. 2340 * @param pDrv Driver to detach from device. 2341 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines. 2342 */ 2343 static int sb16DetachInternal(PPDMDEVINS pDevIns, PSB16STATE pThis, PSB16DRIVER pDrv, uint32_t fFlags) 2344 { 2345 RT_NOREF(fFlags); 2346 2347 /** @todo r=andy Any locking required here? */ 2348 2349 sb16RemoveDrv(pDevIns, pThis, pDrv); 2350 2351 LogFunc(("uLUN=%u, fFlags=0x%x\n", pDrv->uLUN, fFlags)); 2209 2352 return VINF_SUCCESS; 2210 2353 } … … 2218 2361 2219 2362 LogFunc(("iLUN=%u, fFlags=0x%x\n", iLUN, fFlags)); 2363 2364 /** @todo r=andy Any locking required here? */ 2220 2365 2221 2366 PSB16DRIVER pDrv; 2222 2367 int rc2 = sb16AttachInternal(pThis, iLUN, fFlags, &pDrv); 2223 2368 if (RT_SUCCESS(rc2)) 2224 rc2 = sb16CreateDrvStream(&pThis->Out.Cfg, pDrv); 2369 rc2 = sb16AddDrv(pDevIns, pThis, pDrv); 2370 2371 if (RT_FAILURE(rc2)) 2372 LogFunc(("Failed with %Rrc\n", rc2)); 2225 2373 2226 2374 return VINF_SUCCESS; … … 2242 2390 if (pDrv->uLUN == iLUN) 2243 2391 { 2244 int rc2 = sb16DetachInternal(pD rv);2392 int rc2 = sb16DetachInternal(pDevIns, pThis, pDrv, fFlags); 2245 2393 if (RT_SUCCESS(rc2)) 2246 2394 { … … 2303 2451 sb16SpeakerControl(pThis, 0); 2304 2452 sb16Control(pDevIns, pThis, 0); 2305 sb16CmdResetLegacy(p This);2453 sb16CmdResetLegacy(pDevIns, pThis); 2306 2454 } 2307 2455 … … 2317 2465 LogRel2(("SB16: Powering off ...\n")); 2318 2466 2319 PSB16DRIVER pDrv; 2320 RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node) 2321 { 2322 sb16DestroyDrvStreamOut(pDrv); 2467 /* 2468 * Destroy all streams. 2469 */ 2470 sb16StreamClose(pDevIns, pThis, &pThis->StreamOut); 2471 2472 /* 2473 * Destroy all sinks. 2474 */ 2475 if (pThis->pSinkOut) 2476 { 2477 AudioMixerSinkDestroy(pThis->pSinkOut, pDevIns); 2478 pThis->pSinkOut = NULL; 2479 } 2480 2481 /** @todo Add removal + destruction of other streams here once we support them. */ 2482 2483 /* 2484 * Note: Destroy the mixer while powering off and *not* in sb16Destruct, 2485 * giving the mixer the chance to release any references held to 2486 * PDM audio streams it maintains. 2487 */ 2488 if (pThis->pMixer) 2489 { 2490 AudioMixerDestroy(pThis->pMixer, pDevIns); 2491 pThis->pMixer = NULL; 2323 2492 } 2324 2493 } … … 2411 2580 if (uTimerHz > 2048) 2412 2581 return PDMDEV_SET_ERROR(pDevIns, rc, N_("SB16 configuration error: Max TimerHz value is 2048.")); 2582 2583 /* 2584 * Create internal software mixer. 2585 * Must come before we do the device's mixer reset. 2586 */ 2587 rc = AudioMixerCreate("SB16 Mixer", 0 /* uFlags */, &pThis->pMixer); 2588 AssertRCReturn(rc, rc); 2589 2590 AssertRCReturn(rc, rc); 2591 rc = AudioMixerCreateSink(pThis->pMixer, "PCM Output", 2592 AUDMIXSINKDIR_OUTPUT, pDevIns, &pThis->pSinkOut); 2593 AssertRCReturn(rc, rc); 2413 2594 2414 2595 /* … … 2501 2682 } 2502 2683 2503 sb16CmdResetLegacy(p This);2684 sb16CmdResetLegacy(pDevIns, pThis); 2504 2685 2505 2686 #ifdef VBOX_WITH_AUDIO_SB16_ONETIME_INIT
Note:
See TracChangeset
for help on using the changeset viewer.