Changeset 88511 in vbox
- Timestamp:
- Apr 14, 2021 6:56:49 PM (4 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Audio/DrvHostAudioPulseAudio.cpp
r88500 r88511 143 143 /** Pulse playback and buffer metrics. */ 144 144 pa_buffer_attr BufAttr; 145 /** Pointer to Pulse sample peeking buffer. */ 146 const uint8_t *pu8PeekBuf; 147 /** Current size (in bytes) of peeking data in 148 * buffer. */ 145 /** Input: Pointer to Pulse sample peek buffer. */ 146 const uint8_t *pbPeekBuf; 147 /** Input: Current size (in bytes) of peeked data in buffer. */ 149 148 size_t cbPeekBuf; 150 /** Our offset (in bytes) in peekingbuffer. */149 /** Input: Our offset (in bytes) in peek data buffer. */ 151 150 size_t offPeekBuf; 152 /** Asynchronous drain operation. This is used as an indicator of whether153 * w e're currently draining the stream (will be cleaned up before151 /** Output: Asynchronous drain operation. This is used as an indicator of 152 * whether we're currently draining the stream (will be cleaned up before 154 153 * resume/re-enable). */ 155 154 pa_operation *pDrainOp; … … 162 161 * won't do any after-freed accesses.) */ 163 162 pa_operation *pTriggerOp; 164 /** Current latency (in us). */163 /** Output: Current latency (in microsecs). */ 165 164 uint64_t cUsLatency; 166 165 #ifdef LOG_ENABLED 167 /** Start time stamp (in us) of stream playback / recording. */166 /** Creation timestamp (in microsecs) of stream playback / recording. */ 168 167 pa_usec_t tsStartUs; 169 /** Time stamp (in us) when last read from / written to the stream. */168 /** Timestamp (in microsecs) when last read from / written to the stream. */ 170 169 pa_usec_t tsLastReadWrittenUs; 171 170 #endif … … 1038 1037 pStreamPA->pDrv = pThis; 1039 1038 pStreamPA->pDrainOp = NULL; 1040 pStreamPA->p u8PeekBuf = NULL;1039 pStreamPA->pbPeekBuf = NULL; 1041 1040 pStreamPA->SampleSpec.rate = PDMAudioPropsHz(&pCfgReq->Props); 1042 1041 pStreamPA->SampleSpec.channels = PDMAudioPropsChannels(&pCfgReq->Props); … … 1263 1262 if (pStreamPA->Cfg.enmDir == PDMAUDIODIR_OUT) 1264 1263 { 1265 /* Output - Ignore request if we've got a drain running, it will cork it1266 when it completes. */1267 1264 if (pStreamPA->pDrainOp) 1268 1265 { … … 1280 1277 * For input stream we always cork it, but we clean up the peek buffer first. 1281 1278 */ 1282 else if (pStreamPA->pu8PeekBuf) /** @todo Do we need to drop the peek buffer?*/ 1283 { 1279 /** @todo r=bird: It is (probably) not technically be correct to drop the peek buffer 1280 * here when we're only pausing the stream (VM paused) as it means we'll 1281 * risk underruns when later resuming. */ 1282 else if (pStreamPA->pbPeekBuf) /** @todo Do we need to drop the peek buffer?*/ 1283 { 1284 pStreamPA->pbPeekBuf = NULL; 1285 pStreamPA->cbPeekBuf = 0; 1284 1286 pa_stream_drop(pStreamPA->pStream); 1285 pStreamPA->pu8PeekBuf = NULL;1286 1287 } 1287 1288 … … 1474 1475 1475 1476 1476 static uint32_t drvHostAudioPaStreamGetAvailable(PDRVHOSTPULSEAUDIO pThis, PPULSEAUDIOSTREAM pStreamPA) 1477 { 1478 pa_threaded_mainloop_lock(pThis->pMainLoop); 1479 1480 uint32_t cbAvail = 0; 1481 1482 if (PA_STREAM_IS_GOOD(pa_stream_get_state(pStreamPA->pStream))) 1483 { 1484 if (pStreamPA->Cfg.enmDir == PDMAUDIODIR_IN) 1485 { 1486 cbAvail = (uint32_t)pa_stream_readable_size(pStreamPA->pStream); 1487 Log3Func(("cbReadable=%RU32\n", cbAvail)); 1488 } 1489 else if (pStreamPA->Cfg.enmDir == PDMAUDIODIR_OUT) 1490 { 1491 size_t cbWritable = pa_stream_writable_size(pStreamPA->pStream); 1492 1493 Log3Func(("cbWritable=%zu, maxLength=%RU32, minReq=%RU32\n", 1494 cbWritable, pStreamPA->BufAttr.maxlength, pStreamPA->BufAttr.minreq)); 1495 1496 /* Don't report more writable than the PA server can handle. */ 1497 if (cbWritable > pStreamPA->BufAttr.maxlength) 1498 cbWritable = pStreamPA->BufAttr.maxlength; 1499 1500 cbAvail = (uint32_t)cbWritable; 1477 /** 1478 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetReadable} 1479 */ 1480 static DECLCALLBACK(uint32_t) drvHostAudioPaHA_StreamGetReadable(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream) 1481 { 1482 PDRVHOSTPULSEAUDIO pThis = RT_FROM_MEMBER(pInterface, DRVHOSTPULSEAUDIO, IHostAudio); 1483 PPULSEAUDIOSTREAM pStreamPA = (PPULSEAUDIOSTREAM)pStream; 1484 uint32_t cbReadable = 0; 1485 if (pStreamPA->Cfg.enmDir == PDMAUDIODIR_IN) 1486 { 1487 pa_threaded_mainloop_lock(pThis->pMainLoop); 1488 1489 pa_stream_state_t const enmState = pa_stream_get_state(pStreamPA->pStream); 1490 if (PA_STREAM_IS_GOOD(enmState)) 1491 { 1492 size_t cbReadablePa = pa_stream_readable_size(pStreamPA->pStream); 1493 if (cbReadablePa != (size_t)-1) 1494 cbReadable = (uint32_t)cbReadablePa; 1495 else 1496 drvHostAudioPaError(pThis, "pa_stream_readable_size failed on '%s'", pStreamPA->Cfg.szName); 1501 1497 } 1502 1498 else 1503 AssertFailed(); 1504 } 1505 1506 pa_threaded_mainloop_unlock(pThis->pMainLoop); 1507 1508 return cbAvail; 1509 } 1510 1511 1512 /** 1513 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetReadable} 1514 */ 1515 static DECLCALLBACK(uint32_t) drvHostAudioPaHA_StreamGetReadable(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream) 1516 { 1517 return drvHostAudioPaStreamGetAvailable(RT_FROM_MEMBER(pInterface, DRVHOSTPULSEAUDIO, IHostAudio), 1518 (PPULSEAUDIOSTREAM)pStream); 1499 LogFunc(("non-good stream state: %d\n", enmState)); 1500 1501 pa_threaded_mainloop_unlock(pThis->pMainLoop); 1502 } 1503 Log3Func(("returns %#x (%u)\n", cbReadable, cbReadable)); 1504 return cbReadable; 1519 1505 } 1520 1506 … … 1525 1511 static DECLCALLBACK(uint32_t) drvHostAudioPaHA_StreamGetWritable(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream) 1526 1512 { 1527 return drvHostAudioPaStreamGetAvailable(RT_FROM_MEMBER(pInterface, DRVHOSTPULSEAUDIO, IHostAudio), 1528 (PPULSEAUDIOSTREAM)pStream); 1513 PDRVHOSTPULSEAUDIO pThis = RT_FROM_MEMBER(pInterface, DRVHOSTPULSEAUDIO, IHostAudio); 1514 PPULSEAUDIOSTREAM pStreamPA = (PPULSEAUDIOSTREAM)pStream; 1515 uint32_t cbWritable = 0; 1516 if (pStreamPA->Cfg.enmDir == PDMAUDIODIR_OUT) 1517 { 1518 pa_threaded_mainloop_lock(pThis->pMainLoop); 1519 1520 pa_stream_state_t const enmState = pa_stream_get_state(pStreamPA->pStream); 1521 if (PA_STREAM_IS_GOOD(enmState)) 1522 { 1523 size_t cbWritablePa = pa_stream_writable_size(pStreamPA->pStream); 1524 if (cbWritablePa != (size_t)-1) 1525 { 1526 /* Don't report more writable than the PA server can handle. */ 1527 if (cbWritablePa <= pStreamPA->BufAttr.maxlength) 1528 cbWritable = (uint32_t)cbWritablePa; 1529 else 1530 { 1531 Log3Func(("Clamping cbWritablePa=%#zx to maxLength=%#RX32\n", cbWritablePa, pStreamPA->BufAttr.maxlength)); 1532 cbWritable = (uint32_t)pStreamPA->BufAttr.maxlength; 1533 } 1534 } 1535 else 1536 drvHostAudioPaError(pThis, "pa_stream_writable_size failed on '%s'", pStreamPA->Cfg.szName); 1537 } 1538 else 1539 LogFunc(("non-good stream state: %d\n", enmState)); 1540 1541 pa_threaded_mainloop_unlock(pThis->pMainLoop); 1542 } 1543 Log3Func(("returns %#x (%u) [max=%#RX32 min=%#RX32]\n", 1544 cbWritable, cbWritable, pStreamPA->BufAttr.maxlength, pStreamPA->BufAttr.minreq)); 1545 return cbWritable; 1529 1546 } 1530 1547 … … 1539 1556 1540 1557 /* Check PulseAudio's general status. */ 1541 PDMAUDIOSTREAMSTS fStrmSts = PDMAUDIOSTREAMSTS_FLAGS_NONE; 1542 if ( pThis->pContext 1543 && PA_CONTEXT_IS_GOOD(pa_context_get_state(pThis->pContext))) 1544 fStrmSts = PDMAUDIOSTREAMSTS_FLAGS_INITIALIZED | PDMAUDIOSTREAMSTS_FLAGS_ENABLED; 1545 1546 return fStrmSts; 1558 if (pThis->pContext) 1559 { 1560 pa_context_state_t const enmState = pa_context_get_state(pThis->pContext); 1561 if (PA_CONTEXT_IS_GOOD(enmState)) 1562 { 1563 /** @todo should we check the actual stream state? */ 1564 return PDMAUDIOSTREAMSTS_FLAGS_INITIALIZED | PDMAUDIOSTREAMSTS_FLAGS_ENABLED; 1565 } 1566 LogFunc(("non-good context state: %d\n", enmState)); 1567 } 1568 else 1569 LogFunc(("No context!\n")); 1570 return PDMAUDIOSTREAMSTS_FLAGS_NONE; 1547 1571 } 1548 1572 … … 1564 1588 1565 1589 #ifdef LOG_ENABLED 1566 const pa_usec_t tsNowUs = pa_rtclock_now(); 1567 const pa_usec_t tsDeltaPlayedUs = tsNowUs - pStreamPA->tsLastReadWrittenUs; 1568 pStreamPA->tsLastReadWrittenUs = tsNowUs; 1569 Log3Func(("tsDeltaPlayedMs=%RU64\n", tsDeltaPlayedUs / RT_US_1MS)); 1590 const pa_usec_t tsNowUs = pa_rtclock_now(); 1591 Log3Func(("play delta: %RU64 us; cbBuf=%#x\n", tsNowUs - pStreamPA->tsLastReadWrittenUs, cbBuf)); 1592 pStreamPA->tsLastReadWrittenUs = tsNowUs; 1570 1593 #endif 1571 1594 1572 int rc; 1573 size_t const cbWriteable = pa_stream_writable_size(pStreamPA->pStream); 1574 if (cbWriteable != (size_t)-1) 1575 { 1576 size_t cbLeft = RT_MIN(cbWriteable, cbBuf); 1577 Assert(cbLeft > 0 /* At this point we better have *something* to write (DrvAudio checked before calling). */); 1578 if (pa_stream_write(pStreamPA->pStream, pvBuf, cbLeft, NULL /*pfnFree*/, 0 /*offset*/, PA_SEEK_RELATIVE) >= 0) 1579 { 1580 *pcbWritten = (uint32_t)cbLeft; 1581 rc = VINF_SUCCESS; 1595 /* 1596 * Using a loop here so we can take maxlength into account when writing. 1597 */ 1598 int rc = VINF_SUCCESS; 1599 uint32_t cbTotalWritten = 0; 1600 uint32_t iLoop; 1601 for (iLoop = 0; ; iLoop++) 1602 { 1603 size_t const cbWriteable = pa_stream_writable_size(pStreamPA->pStream); 1604 if ( cbWriteable != (size_t)-1 1605 && cbWriteable >= PDMAudioPropsFrameSize(&pStreamPA->Cfg.Props)) 1606 { 1607 uint32_t cbToWrite = (uint32_t)RT_MIN(RT_MIN(cbWriteable, pStreamPA->BufAttr.maxlength), cbBuf); 1608 cbToWrite = PDMAudioPropsFloorBytesToFrame(&pStreamPA->Cfg.Props, cbToWrite); 1609 if (pa_stream_write(pStreamPA->pStream, pvBuf, cbToWrite, NULL /*pfnFree*/, 0 /*offset*/, PA_SEEK_RELATIVE) >= 0) 1610 { 1611 cbTotalWritten += cbToWrite; 1612 cbBuf -= cbToWrite; 1613 if (!cbBuf) 1614 break; 1615 pvBuf = (uint8_t const *)pvBuf + cbToWrite; 1616 Log3Func(("%#x left to write\n", cbBuf)); 1617 } 1618 else 1619 { 1620 rc = drvHostAudioPaError(pStreamPA->pDrv, "Failed to write to output stream"); 1621 break; 1622 } 1582 1623 } 1583 1624 else 1584 rc = drvHostAudioPaError(pStreamPA->pDrv, "Failed to write to output stream"); 1585 } 1625 { 1626 if (cbWriteable == (size_t)-1) 1627 rc = drvHostAudioPaError(pStreamPA->pDrv, "pa_stream_writable_size failed on '%s'", pStreamPA->Cfg.szName); 1628 break; 1629 } 1630 } 1631 1632 pa_threaded_mainloop_unlock(pThis->pMainLoop); 1633 1634 *pcbWritten = cbTotalWritten; 1635 if (RT_SUCCESS(rc) || cbTotalWritten == 0) 1636 { /* likely */ } 1586 1637 else 1587 rc = drvHostAudioPaError(pStreamPA->pDrv, "Failed to determine output data size"); 1588 1589 pa_threaded_mainloop_unlock(pThis->pMainLoop); 1638 { 1639 LogFunc(("Supressing %Rrc because we wrote %#x bytes\n", rc, cbTotalWritten)); 1640 rc = VINF_SUCCESS; 1641 } 1642 Log3Func(("returns %Rrc *pcbWritten=%#x iLoop=%u\n", rc, cbTotalWritten, iLoop)); 1590 1643 return rc; 1591 1644 } … … 1605 1658 AssertPtrReturn(pcbRead, VERR_INVALID_POINTER); 1606 1659 1607 /* We should only call pa_stream_readable_size() once and trust the first value. */ 1660 #ifdef LOG_ENABLED 1661 const pa_usec_t tsNowUs = pa_rtclock_now(); 1662 Log3Func(("capture delta: %RU64 us; cbBuf=%#x\n", tsNowUs - pStreamPA->tsLastReadWrittenUs, cbBuf)); 1663 pStreamPA->tsLastReadWrittenUs = tsNowUs; 1664 #endif 1665 1666 /* 1667 * If we have left over peek buffer space from the last call, 1668 * copy out the data from there. 1669 */ 1670 uint32_t cbTotalRead = 0; 1671 if ( pStreamPA->pbPeekBuf 1672 && pStreamPA->offPeekBuf < pStreamPA->cbPeekBuf) 1673 { 1674 uint32_t cbToCopy = pStreamPA->cbPeekBuf - pStreamPA->offPeekBuf; 1675 if (cbToCopy >= cbBuf) 1676 { 1677 memcpy(pvBuf, &pStreamPA->pbPeekBuf[pStreamPA->offPeekBuf], cbBuf); 1678 pStreamPA->offPeekBuf += cbBuf; 1679 *pcbRead = cbBuf; 1680 if (cbToCopy == cbBuf) 1681 { 1682 pa_threaded_mainloop_lock(pThis->pMainLoop); 1683 pStreamPA->pbPeekBuf = NULL; 1684 pStreamPA->cbPeekBuf = 0; 1685 pa_stream_drop(pStreamPA->pStream); 1686 pa_threaded_mainloop_unlock(pThis->pMainLoop); 1687 } 1688 Log3Func(("returns *pcbRead=%#x from prev peek buf (%#x/%#x)\n", cbBuf, pStreamPA->offPeekBuf, pStreamPA->cbPeekBuf)); 1689 return VINF_SUCCESS; 1690 } 1691 1692 memcpy(pvBuf, &pStreamPA->pbPeekBuf[pStreamPA->offPeekBuf], cbToCopy); 1693 cbBuf -= cbToCopy; 1694 pvBuf = (uint8_t *)pvBuf + cbToCopy; 1695 cbTotalRead += cbToCopy; 1696 pStreamPA->offPeekBuf = pStreamPA->cbPeekBuf; 1697 } 1698 1699 /* 1700 * Copy out what we can. 1701 */ 1702 int rc = VINF_SUCCESS; 1608 1703 pa_threaded_mainloop_lock(pThis->pMainLoop); 1609 size_t cbAvail = pa_stream_readable_size(pStreamPA->pStream); 1610 pa_threaded_mainloop_unlock(pThis->pMainLoop); 1611 1612 if (cbAvail == (size_t)-1) 1613 return drvHostAudioPaError(pStreamPA->pDrv, "Failed to determine input data size"); 1614 1615 /* If the buffer was not dropped last call, add what remains. */ 1616 if (pStreamPA->pu8PeekBuf) 1617 { 1618 Assert(pStreamPA->cbPeekBuf >= pStreamPA->offPeekBuf); 1619 cbAvail += (pStreamPA->cbPeekBuf - pStreamPA->offPeekBuf); 1620 } 1621 1622 Log3Func(("cbAvail=%zu\n", cbAvail)); 1623 1624 if (!cbAvail) /* No data? Bail out. */ 1625 { 1626 *pcbRead = 0; 1627 return VINF_SUCCESS; 1628 } 1629 1630 int rc = VINF_SUCCESS; 1631 1632 size_t cbToRead = RT_MIN(cbAvail, cbBuf); 1633 1634 Log3Func(("cbToRead=%zu, cbAvail=%zu, offPeekBuf=%zu, cbPeekBuf=%zu\n", 1635 cbToRead, cbAvail, pStreamPA->offPeekBuf, pStreamPA->cbPeekBuf)); 1636 1637 uint32_t cbReadTotal = 0; 1638 1639 while (cbToRead) 1640 { 1641 /* If there is no data, do another peek. */ 1642 if (!pStreamPA->pu8PeekBuf) 1643 { 1644 pa_threaded_mainloop_lock(pThis->pMainLoop); 1645 pa_stream_peek(pStreamPA->pStream, 1646 (const void**)&pStreamPA->pu8PeekBuf, &pStreamPA->cbPeekBuf); 1647 pa_threaded_mainloop_unlock(pThis->pMainLoop); 1648 1649 pStreamPA->offPeekBuf = 0; 1650 1651 /* No data anymore? 1652 * Note: If there's a data hole (cbPeekBuf then contains the length of the hole) 1653 * we need to drop the stream lateron. */ 1654 if ( !pStreamPA->pu8PeekBuf 1655 && !pStreamPA->cbPeekBuf) 1704 while (cbBuf > 0) 1705 { 1706 /* 1707 * Drop the old peek buffer first, if we have one. 1708 */ 1709 if (pStreamPA->pbPeekBuf) 1710 { 1711 Assert(pStreamPA->offPeekBuf >= pStreamPA->cbPeekBuf); 1712 pStreamPA->pbPeekBuf = NULL; 1713 pStreamPA->cbPeekBuf = 0; 1714 pa_stream_drop(pStreamPA->pStream); 1715 } 1716 1717 /* 1718 * Check if there is anything to read, the get the peek buffer for it. 1719 */ 1720 size_t cbAvail = pa_stream_readable_size(pStreamPA->pStream); 1721 if (cbAvail > 0 && cbAvail != (size_t)-1) 1722 { 1723 pStreamPA->pbPeekBuf = NULL; 1724 pStreamPA->cbPeekBuf = 0; 1725 int rcPa = pa_stream_peek(pStreamPA->pStream, (const void **)&pStreamPA->pbPeekBuf, &pStreamPA->cbPeekBuf); 1726 if (rcPa == 0) 1656 1727 { 1728 if (pStreamPA->cbPeekBuf) 1729 { 1730 if (pStreamPA->pbPeekBuf) 1731 { 1732 /* 1733 * We got data back. Copy it into the return buffer, return if it's full. 1734 */ 1735 if (cbBuf < pStreamPA->cbPeekBuf) 1736 { 1737 memcpy(pvBuf, pStreamPA->pbPeekBuf, cbBuf); 1738 cbTotalRead += cbBuf; 1739 pStreamPA->offPeekBuf = cbBuf; 1740 cbBuf = 0; 1741 break; 1742 } 1743 memcpy(pvBuf, pStreamPA->pbPeekBuf, pStreamPA->cbPeekBuf); 1744 cbBuf -= pStreamPA->cbPeekBuf; 1745 pvBuf = (uint8_t *)pvBuf + pStreamPA->cbPeekBuf; 1746 cbTotalRead += pStreamPA->cbPeekBuf; 1747 1748 pStreamPA->pbPeekBuf = NULL; 1749 } 1750 else 1751 { 1752 /* 1753 * We got a hole (drop needed). We will skip it as we leave it to 1754 * the device's DMA engine to fill in buffer gaps with silence. 1755 */ 1756 LogFunc(("pa_stream_peek returned a %#zx (%zu) byte hole - skipping.\n", 1757 pStreamPA->cbPeekBuf, pStreamPA->cbPeekBuf)); 1758 } 1759 pStreamPA->cbPeekBuf = 0; 1760 pa_stream_drop(pStreamPA->pStream); 1761 } 1762 else 1763 { 1764 Assert(!pStreamPA->pbPeekBuf); 1765 LogFunc(("pa_stream_peek returned empty buffer\n")); 1766 break; 1767 } 1768 } 1769 else 1770 { 1771 rc = drvHostAudioPaError(pStreamPA->pDrv, "pa_stream_peek failed on '%s' (%d)", pStreamPA->Cfg.szName, rcPa); 1772 pStreamPA->pbPeekBuf = NULL; 1773 pStreamPA->cbPeekBuf = 0; 1657 1774 break; 1658 1775 } 1659 1776 } 1660 1661 Assert(pStreamPA->cbPeekBuf >= pStreamPA->offPeekBuf); 1662 size_t cbToWrite = RT_MIN(pStreamPA->cbPeekBuf - pStreamPA->offPeekBuf, cbToRead); 1663 1664 Log3Func(("cbToRead=%zu, cbToWrite=%zu, offPeekBuf=%zu, cbPeekBuf=%zu, pu8PeekBuf=%p\n", 1665 cbToRead, cbToWrite, 1666 pStreamPA->offPeekBuf, pStreamPA->cbPeekBuf, pStreamPA->pu8PeekBuf)); 1667 1668 if ( cbToWrite 1669 /* Only copy data if it's not a data hole (see above). */ 1670 && pStreamPA->pu8PeekBuf 1671 && pStreamPA->cbPeekBuf) 1672 { 1673 memcpy((uint8_t *)pvBuf + cbReadTotal, pStreamPA->pu8PeekBuf + pStreamPA->offPeekBuf, cbToWrite); 1674 1675 Assert(cbToRead >= cbToWrite); 1676 cbToRead -= cbToWrite; 1677 cbReadTotal += cbToWrite; 1678 1679 pStreamPA->offPeekBuf += cbToWrite; 1680 Assert(pStreamPA->offPeekBuf <= pStreamPA->cbPeekBuf); 1681 } 1682 1683 if (/* Nothing to write anymore? Drop the buffer. */ 1684 !cbToWrite 1685 /* Was there a hole in the peeking buffer? Drop it. */ 1686 || !pStreamPA->pu8PeekBuf 1687 /* If the buffer is done, drop it. */ 1688 || pStreamPA->offPeekBuf == pStreamPA->cbPeekBuf) 1689 { 1690 pa_threaded_mainloop_lock(pThis->pMainLoop); 1691 pa_stream_drop(pStreamPA->pStream); 1692 pa_threaded_mainloop_unlock(pThis->pMainLoop); 1693 1694 pStreamPA->pu8PeekBuf = NULL; 1695 } 1696 } 1697 1698 if (RT_SUCCESS(rc)) 1699 *pcbRead = cbReadTotal; 1777 else 1778 { 1779 if (cbAvail != (size_t)-1) 1780 rc = drvHostAudioPaError(pStreamPA->pDrv, "pa_stream_readable_size failed on '%s'", pStreamPA->Cfg.szName); 1781 break; 1782 } 1783 } 1784 pa_threaded_mainloop_unlock(pThis->pMainLoop); 1785 1786 *pcbRead = cbTotalRead; 1787 if (RT_SUCCESS(rc) || cbTotalRead == 0) 1788 { /* likely */ } 1789 else 1790 { 1791 LogFunc(("Supressing %Rrc because we're returning %#x bytes\n", rc, cbTotalRead)); 1792 rc = VINF_SUCCESS; 1793 } 1794 Log3Func(("returns %Rrc *pcbRead=%#x (%#x left, peek %#x/%#x)\n", 1795 rc, cbTotalRead, cbBuf, pStreamPA->offPeekBuf, pStreamPA->cbPeekBuf)); 1700 1796 return rc; 1701 1797 }
Note:
See TracChangeset
for help on using the changeset viewer.