VirtualBox

Changeset 88386 in vbox for trunk


Ignore:
Timestamp:
Apr 7, 2021 9:55:22 AM (4 years ago)
Author:
vboxsync
Message:

DrvHostAudioPulseAudio: Fail if pa_context_connect() fails. Baked drvHostPulseAudioHA_Init into the constructor and drvHostPulseAudioHA_Shutdown into the power off callback and destructor callbacks. (untested) bugref:9890

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Audio/DrvHostAudioPulseAudio.cpp

    r88380 r88386  
    6666*   Structures                                                                                                                   *
    6767*********************************************************************************************************************************/
     68/**
     69 * Callback context for the server init context state changed callback.
     70 */
     71typedef 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. */
     79typedef PULSEAUDIOSTATECHGCTX *PPULSEAUDIOSTATECHGCTX;
    6880
    6981/**
     
    97109     *  VMs are running at the same time. */
    98110    char                  szStreamName[64];
     111
     112    /** Don't want to put this on the stack... */
     113    PULSEAUDIOSTATECHGCTX   InitStateChgCtx;
    99114} DRVHOSTPULSEAUDIO, *PDRVHOSTPULSEAUDIO;
    100115
     
    152167
    153168
    154 /**
    155  * Callback context for the server init context state changed callback.
    156  */
    157 typedef struct PULSEAUDIOSTATECHGCTX
    158 {
    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 
    168169/*
    169170 * To allow running on systems with PulseAudio < 0.9.11.
     
    639640    if (pStream)
    640641        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     do
    677     {
    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 connecting
    706          * 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                 else
    730                 {
    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             else
    739                 LogRel(("PulseAudio: Waiting for context to become ready failed with %Rrc\n", rc));
    740         }
    741         else
    742             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 
    771642    LogFlowFuncLeaveRC(rc);
    772643    return rc;
     
    13981269
    13991270/**
    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 /**
    14311271 * @interface_method_impl{PDMIHOSTAUDIO,pfnGetConfig}
    14321272 */
     
    16451485
    16461486/**
     1487 * @interface_method_impl{PDMDRVREG,pfnPowerOff}
     1488 */
     1489static 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/**
    16471515 * Destructs a PulseAudio Audio driver instance.
    16481516 *
     
    16531521    PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
    16541522    LogFlowFuncEnter();
     1523    drvHostPulseAudioPowerOff(pDrvIns);
     1524    LogFlowFuncLeave();
    16551525}
    16561526
     
    16701540    LogRel(("Audio: Initializing PulseAudio driver\n"));
    16711541
     1542    /*
     1543     * Initialize instance data.
     1544     */
    16721545    pThis->pDrvIns                   = pDrvIns;
    16731546    /* IBase */
    16741547    pDrvIns->IBase.pfnQueryInterface = drvHostPulseAudioQueryInterface;
    16751548    /* IHostAudio */
    1676     pThis->IHostAudio.pfnInit               = drvHostPulseAudioHA_Init;
    1677     pThis->IHostAudio.pfnShutdown           = drvHostPulseAudioHA_Shutdown;
     1549    pThis->IHostAudio.pfnInit               = NULL;
     1550    pThis->IHostAudio.pfnShutdown           = NULL;
    16781551    pThis->IHostAudio.pfnGetConfig          = drvHostPulseAudioHA_GetConfig;
    16791552    pThis->IHostAudio.pfnGetStatus          = drvHostPulseAudioHA_GetStatus;
     
    16891562    pThis->IHostAudio.pfnStreamGetPending   = NULL;
    16901563
     1564    /*
     1565     * Read configuration.
     1566     */
    16911567    int rc2 = CFGMR3QueryString(pCfg, "StreamName", pThis->szStreamName, sizeof(pThis->szStreamName));
    16921568    AssertMsgRCReturn(rc2, ("Confguration error: No/bad \"StreamName\" value, rc=%Rrc\n", rc2), rc2);
    16931569
    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;
    16951656}
    16961657
     
    17401701    NULL,
    17411702    /* pfnPowerOff */
    1742     NULL,
     1703    drvHostPulseAudioPowerOff,
    17431704    /* pfnSoftReset */
    17441705    NULL,
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette