- Timestamp:
- Apr 7, 2021 9:55:22 AM (4 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Audio/DrvHostAudioPulseAudio.cpp
r88380 r88386 66 66 * Structures * 67 67 *********************************************************************************************************************************/ 68 /** 69 * Callback context for the server init context state changed callback. 70 */ 71 typedef struct PULSEAUDIOSTATECHGCTX 72 { 73 /** The event semaphore. */ 74 RTSEMEVENT hEvtInit; 75 /** The returned context state. */ 76 volatile pa_context_state_t enmCtxState; 77 } PULSEAUDIOSTATECHGCTX; 78 /** Pointer to a server init context state changed callback context. */ 79 typedef PULSEAUDIOSTATECHGCTX *PPULSEAUDIOSTATECHGCTX; 68 80 69 81 /** … … 97 109 * VMs are running at the same time. */ 98 110 char szStreamName[64]; 111 112 /** Don't want to put this on the stack... */ 113 PULSEAUDIOSTATECHGCTX InitStateChgCtx; 99 114 } DRVHOSTPULSEAUDIO, *PDRVHOSTPULSEAUDIO; 100 115 … … 152 167 153 168 154 /**155 * Callback context for the server init context state changed callback.156 */157 typedef struct PULSEAUDIOSTATECHGCTX158 {159 /** The event semaphore. */160 RTSEMEVENT hEvtInit;161 /** The returned context state. */162 volatile pa_context_state_t enmCtxState;163 } PULSEAUDIOSTATECHGCTX;164 /** Pointer to a server init context state changed callback context. */165 typedef PULSEAUDIOSTATECHGCTX *PPULSEAUDIOSTATECHGCTX;166 167 168 169 /* 169 170 * To allow running on systems with PulseAudio < 0.9.11. … … 639 640 if (pStream) 640 641 pa_stream_unref(pStream); 641 LogFlowFuncLeaveRC(rc);642 return rc;643 }644 645 646 /**647 * @interface_method_impl{PDMIHOSTAUDIO,pfnInit}648 */649 static DECLCALLBACK(int) drvHostPulseAudioHA_Init(PPDMIHOSTAUDIO pInterface)650 {651 AssertPtrReturn(pInterface, VERR_INVALID_POINTER);652 653 PDRVHOSTPULSEAUDIO pThis = PDMIHOSTAUDIO_2_DRVHOSTPULSEAUDIO(pInterface);654 655 LogFlowFuncEnter();656 657 int rc = audioLoadPulseLib();658 if (RT_FAILURE(rc))659 {660 LogRel(("PulseAudio: Failed to load the PulseAudio shared library! Error %Rrc\n", rc));661 return rc;662 }663 664 LogRel(("PulseAudio: Using v%s\n", pa_get_library_version()));665 666 pThis->fAbortLoop = false;667 pThis->pMainLoop = pa_threaded_mainloop_new();668 if (!pThis->pMainLoop)669 {670 LogRel(("PulseAudio: Failed to allocate main loop: %s\n", pa_strerror(pa_context_errno(pThis->pContext))));671 return VERR_NO_MEMORY;672 }673 674 bool fLocked = false;675 676 do677 {678 if (!(pThis->pContext = pa_context_new(pa_threaded_mainloop_get_api(pThis->pMainLoop), "VirtualBox")))679 {680 LogRel(("PulseAudio: Failed to allocate context: %s\n",681 pa_strerror(pa_context_errno(pThis->pContext))));682 rc = VERR_NO_MEMORY;683 break;684 }685 686 if (pa_threaded_mainloop_start(pThis->pMainLoop) < 0)687 {688 LogRel(("PulseAudio: Failed to start threaded mainloop: %s\n",689 pa_strerror(pa_context_errno(pThis->pContext))));690 rc = VERR_AUDIO_BACKEND_INIT_FAILED;691 break;692 }693 694 PULSEAUDIOSTATECHGCTX InitStateChgCtx;695 InitStateChgCtx.hEvtInit = NIL_RTSEMEVENT;696 InitStateChgCtx.enmCtxState = PA_CONTEXT_UNCONNECTED;697 rc = RTSemEventCreate(&InitStateChgCtx.hEvtInit);698 if (RT_FAILURE(rc))699 {700 LogRel(("PulseAudio: Failed to create init event semaphore: %Rrc\n", rc));701 break;702 }703 704 /*705 * Install a dedicated init state callback so we can do a timed wait on our own event semaphore if connecting706 * to the pulseaudio server takes too long.707 */708 pa_context_set_state_callback(pThis->pContext, paContextCbStateChangedInit, &InitStateChgCtx /* pvUserData */);709 710 pa_threaded_mainloop_lock(pThis->pMainLoop);711 fLocked = true;712 713 if (!pa_context_connect(pThis->pContext, NULL /* pszServer */,714 PA_CONTEXT_NOFLAGS, NULL))715 {716 /* Wait on our init event semaphore and time out if connecting to the pulseaudio server takes too long. */717 pa_threaded_mainloop_unlock(pThis->pMainLoop);718 fLocked = false;719 720 rc = RTSemEventWait(InitStateChgCtx.hEvtInit, RT_MS_10SEC); /* 10 seconds should be plenty. */721 if (RT_SUCCESS(rc))722 {723 if (InitStateChgCtx.enmCtxState != PA_CONTEXT_READY)724 {725 LogRel(("PulseAudio: Failed to initialize context (state %d, rc=%Rrc)\n", InitStateChgCtx.enmCtxState, rc));726 if (RT_SUCCESS(rc))727 rc = VERR_AUDIO_BACKEND_INIT_FAILED;728 }729 else730 {731 pa_threaded_mainloop_lock(pThis->pMainLoop);732 fLocked = true;733 734 /* Install the main state changed callback to know if something happens to our acquired context. */735 pa_context_set_state_callback(pThis->pContext, paContextCbStateChanged, pThis /* pvUserData */);736 }737 }738 else739 LogRel(("PulseAudio: Waiting for context to become ready failed with %Rrc\n", rc));740 }741 else742 LogRel(("PulseAudio: Failed to connect to server: %s\n",743 pa_strerror(pa_context_errno(pThis->pContext))));744 745 RTSemEventDestroy(InitStateChgCtx.hEvtInit);746 }747 while (0);748 749 if (fLocked)750 pa_threaded_mainloop_unlock(pThis->pMainLoop);751 752 if (RT_FAILURE(rc))753 {754 if (pThis->pMainLoop)755 pa_threaded_mainloop_stop(pThis->pMainLoop);756 757 if (pThis->pContext)758 {759 pa_context_disconnect(pThis->pContext);760 pa_context_unref(pThis->pContext);761 pThis->pContext = NULL;762 }763 764 if (pThis->pMainLoop)765 {766 pa_threaded_mainloop_free(pThis->pMainLoop);767 pThis->pMainLoop = NULL;768 }769 }770 771 642 LogFlowFuncLeaveRC(rc); 772 643 return rc; … … 1398 1269 1399 1270 /** 1400 * @interface_method_impl{PDMIHOSTAUDIO,pfnShutdown}1401 */1402 static DECLCALLBACK(void) drvHostPulseAudioHA_Shutdown(PPDMIHOSTAUDIO pInterface)1403 {1404 AssertPtrReturnVoid(pInterface);1405 1406 PDRVHOSTPULSEAUDIO pThis = PDMIHOSTAUDIO_2_DRVHOSTPULSEAUDIO(pInterface);1407 1408 LogFlowFuncEnter();1409 1410 if (pThis->pMainLoop)1411 pa_threaded_mainloop_stop(pThis->pMainLoop);1412 1413 if (pThis->pContext)1414 {1415 pa_context_disconnect(pThis->pContext);1416 pa_context_unref(pThis->pContext);1417 pThis->pContext = NULL;1418 }1419 1420 if (pThis->pMainLoop)1421 {1422 pa_threaded_mainloop_free(pThis->pMainLoop);1423 pThis->pMainLoop = NULL;1424 }1425 1426 LogFlowFuncLeave();1427 }1428 1429 1430 /**1431 1271 * @interface_method_impl{PDMIHOSTAUDIO,pfnGetConfig} 1432 1272 */ … … 1645 1485 1646 1486 /** 1487 * @interface_method_impl{PDMDRVREG,pfnPowerOff} 1488 */ 1489 static DECLCALLBACK(void) drvHostPulseAudioPowerOff(PPDMDRVINS pDrvIns) 1490 { 1491 PDRVHOSTPULSEAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTPULSEAUDIO); 1492 LogFlowFuncEnter(); 1493 1494 if (pThis->pMainLoop) 1495 pa_threaded_mainloop_stop(pThis->pMainLoop); 1496 1497 if (pThis->pContext) 1498 { 1499 pa_context_disconnect(pThis->pContext); 1500 pa_context_unref(pThis->pContext); 1501 pThis->pContext = NULL; 1502 } 1503 1504 if (pThis->pMainLoop) 1505 { 1506 pa_threaded_mainloop_free(pThis->pMainLoop); 1507 pThis->pMainLoop = NULL; 1508 } 1509 1510 LogFlowFuncLeave(); 1511 } 1512 1513 1514 /** 1647 1515 * Destructs a PulseAudio Audio driver instance. 1648 1516 * … … 1653 1521 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns); 1654 1522 LogFlowFuncEnter(); 1523 drvHostPulseAudioPowerOff(pDrvIns); 1524 LogFlowFuncLeave(); 1655 1525 } 1656 1526 … … 1670 1540 LogRel(("Audio: Initializing PulseAudio driver\n")); 1671 1541 1542 /* 1543 * Initialize instance data. 1544 */ 1672 1545 pThis->pDrvIns = pDrvIns; 1673 1546 /* IBase */ 1674 1547 pDrvIns->IBase.pfnQueryInterface = drvHostPulseAudioQueryInterface; 1675 1548 /* IHostAudio */ 1676 pThis->IHostAudio.pfnInit = drvHostPulseAudioHA_Init;1677 pThis->IHostAudio.pfnShutdown = drvHostPulseAudioHA_Shutdown;1549 pThis->IHostAudio.pfnInit = NULL; 1550 pThis->IHostAudio.pfnShutdown = NULL; 1678 1551 pThis->IHostAudio.pfnGetConfig = drvHostPulseAudioHA_GetConfig; 1679 1552 pThis->IHostAudio.pfnGetStatus = drvHostPulseAudioHA_GetStatus; … … 1689 1562 pThis->IHostAudio.pfnStreamGetPending = NULL; 1690 1563 1564 /* 1565 * Read configuration. 1566 */ 1691 1567 int rc2 = CFGMR3QueryString(pCfg, "StreamName", pThis->szStreamName, sizeof(pThis->szStreamName)); 1692 1568 AssertMsgRCReturn(rc2, ("Confguration error: No/bad \"StreamName\" value, rc=%Rrc\n", rc2), rc2); 1693 1569 1694 return VINF_SUCCESS; 1570 /* 1571 * Load the pulse audio library. 1572 */ 1573 int rc = audioLoadPulseLib(); 1574 if (RT_SUCCESS(rc)) 1575 LogRel(("PulseAudio: Using version %s\n", pa_get_library_version())); 1576 else 1577 { 1578 LogRel(("PulseAudio: Failed to load the PulseAudio shared library! Error %Rrc\n", rc)); 1579 return rc; 1580 } 1581 1582 /* 1583 * Set up the basic pulse audio bits (remember the destructore is always called). 1584 */ 1585 //pThis->fAbortLoop = false; 1586 pThis->pMainLoop = pa_threaded_mainloop_new(); 1587 if (!pThis->pMainLoop) 1588 { 1589 LogRel(("PulseAudio: Failed to allocate main loop: %s\n", pa_strerror(pa_context_errno(pThis->pContext)))); 1590 return VERR_NO_MEMORY; 1591 } 1592 1593 pThis->pContext = pa_context_new(pa_threaded_mainloop_get_api(pThis->pMainLoop), "VirtualBox"); 1594 if (!pThis->pContext) 1595 { 1596 LogRel(("PulseAudio: Failed to allocate context: %s\n", pa_strerror(pa_context_errno(pThis->pContext)))); 1597 return VERR_NO_MEMORY; 1598 } 1599 1600 if (pa_threaded_mainloop_start(pThis->pMainLoop) < 0) 1601 { 1602 LogRel(("PulseAudio: Failed to start threaded mainloop: %s\n", pa_strerror(pa_context_errno(pThis->pContext)))); 1603 return VERR_AUDIO_BACKEND_INIT_FAILED; 1604 } 1605 1606 /* 1607 * Connect to the pulse audio server. 1608 * 1609 * We install an init state callback so we can do a timed wait in case 1610 * connecting to the pulseaudio server should take too long. 1611 */ 1612 pThis->InitStateChgCtx.hEvtInit = NIL_RTSEMEVENT; 1613 pThis->InitStateChgCtx.enmCtxState = PA_CONTEXT_UNCONNECTED; 1614 rc = RTSemEventCreate(&pThis->InitStateChgCtx.hEvtInit); 1615 AssertLogRelRCReturn(rc, rc); 1616 1617 pa_threaded_mainloop_lock(pThis->pMainLoop); 1618 pa_context_set_state_callback(pThis->pContext, paContextCbStateChangedInit, &pThis->InitStateChgCtx); 1619 if (!pa_context_connect(pThis->pContext, NULL /* pszServer */, PA_CONTEXT_NOFLAGS, NULL)) 1620 { 1621 pa_threaded_mainloop_unlock(pThis->pMainLoop); 1622 1623 rc = RTSemEventWait(pThis->InitStateChgCtx.hEvtInit, RT_MS_10SEC); /* 10 seconds should be plenty. */ 1624 if (RT_SUCCESS(rc)) 1625 { 1626 if (pThis->InitStateChgCtx.enmCtxState == PA_CONTEXT_READY) 1627 { 1628 /* Install the main state changed callback to know if something happens to our acquired context. */ 1629 pa_threaded_mainloop_lock(pThis->pMainLoop); 1630 pa_context_set_state_callback(pThis->pContext, paContextCbStateChanged, pThis /* pvUserData */); 1631 pa_threaded_mainloop_unlock(pThis->pMainLoop); 1632 } 1633 else 1634 { 1635 LogRel(("PulseAudio: Failed to initialize context (state %d, rc=%Rrc)\n", pThis->InitStateChgCtx.enmCtxState, rc)); 1636 rc = VERR_AUDIO_BACKEND_INIT_FAILED; 1637 } 1638 } 1639 else 1640 { 1641 LogRel(("PulseAudio: Waiting for context to become ready failed: %Rrc\n", rc)); 1642 rc = VERR_AUDIO_BACKEND_INIT_FAILED; 1643 } 1644 } 1645 else 1646 { 1647 pa_threaded_mainloop_unlock(pThis->pMainLoop); 1648 LogRel(("PulseAudio: Failed to connect to server: %s\n", pa_strerror(pa_context_errno(pThis->pContext)))); 1649 rc = VERR_AUDIO_BACKEND_INIT_FAILED; /* bird: This used to be VINF_SUCCESS. */ 1650 } 1651 1652 RTSemEventDestroy(pThis->InitStateChgCtx.hEvtInit); 1653 pThis->InitStateChgCtx.hEvtInit = NIL_RTSEMEVENT; 1654 1655 return rc; 1695 1656 } 1696 1657 … … 1740 1701 NULL, 1741 1702 /* pfnPowerOff */ 1742 NULL,1703 drvHostPulseAudioPowerOff, 1743 1704 /* pfnSoftReset */ 1744 1705 NULL,
Note:
See TracChangeset
for help on using the changeset viewer.