VirtualBox

Changeset 88478 in vbox for trunk/src/VBox/Devices/Audio


Ignore:
Timestamp:
Apr 13, 2021 12:03:47 AM (4 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
143737
Message:

DrvHostAudioPulse: Implemented basic device enumeration. bugref:9890

Location:
trunk/src/VBox/Devices/Audio
Files:
3 edited

Legend:

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

    r88477 r88478  
    2424#include <VBox/vmm/pdmaudioifs.h>
    2525#include <VBox/vmm/pdmaudioinline.h>
     26#include <VBox/vmm/pdmaudiohostenuminline.h>
    2627
    2728#include <stdio.h>
     
    8990typedef struct PULSEAUDIOENUMCBCTX
    9091{
    91     /** Pointer to host backend driver. */
    92     PDRVHOSTPULSEAUDIO      pDrv;
    9392    /** Pointer to PulseAudio's threaded main loop. */
    9493    pa_threaded_mainloop   *pMainLoop;
    9594    /** Enumeration flags, PULSEAUDIOENUMCBFLAGS_XXX. */
    9695    uint32_t                fFlags;
    97     /** VBox status code for the operation. */
     96    /** VBox status code for the operation.
     97     * The caller sets this to VERR_AUDIO_ENUMERATION_FAILED, the callback never
     98     * uses that status code. */
    9899    int32_t                 rcEnum;
    99     /** Number of found input devices. */
    100     uint8_t                 cDevIn;
    101     /** Number of found output devices. */
    102     uint8_t                 cDevOut;
    103100    /** Name of default sink being used. Must be free'd using RTStrFree(). */
    104101    char                   *pszDefaultSink;
    105102    /** Name of default source being used. Must be free'd using RTStrFree(). */
    106103    char                   *pszDefaultSource;
     104    /** The device enumeration to fill, NULL if pfnGetConfig context.   */
     105    PPDMAUDIOHOSTENUM       pDeviceEnum;
    107106} PULSEAUDIOENUMCBCTX;
    108107/** Pointer to an enumeration callback context. */
    109108typedef PULSEAUDIOENUMCBCTX *PPULSEAUDIOENUMCBCTX;
     109
     110
     111/**
     112 * Pulse audio device enumeration entry.
     113 */
     114typedef struct PULSEAUDIODEVENTRY
     115{
     116    /** The part we share with others. */
     117    PDMAUDIOHOSTDEV         Core;
     118    /** The pulse audio name.
     119     * @note Kind of must use fixed size field here as that allows
     120     *       PDMAudioHostDevDup() and PDMAudioHostEnumCopy() to work. */
     121    RT_FLEXIBLE_ARRAY_EXTENSION
     122    char                    szPulseName[RT_FLEXIBLE_ARRAY];
     123} PULSEAUDIODEVENTRY;
     124/** Pointer to a pulse audio device enumeration entry. */
     125typedef PULSEAUDIODEVENTRY *PPULSEAUDIODEVENTRY;
    110126
    111127
     
    338354
    339355/**
     356 * Worker for drvHostAudioPaEnumSourceCallback() and
     357 * drvHostAudioPaEnumSinkCallback() that adds an entry to the enumeration
     358 * result.
     359 */
     360static void drvHostAudioPaEnumAddDevice(PPULSEAUDIOENUMCBCTX pCbCtx, PDMAUDIODIR enmDir, const char *pszName,
     361                                        const char *pszDesc, uint8_t cChannelsInput, uint8_t cChannelsOutput,
     362                                        const char *pszDefaultName)
     363{
     364    size_t const cchName = strlen(pszName);
     365    PPULSEAUDIODEVENTRY pDev = (PPULSEAUDIODEVENTRY)PDMAudioHostDevAlloc(RT_UOFFSETOF(PULSEAUDIODEVENTRY, szPulseName)
     366                                                                         + RT_ALIGN_Z(cchName + 1, 16));
     367    if (pDev != NULL)
     368    {
     369        memcpy(pDev->szPulseName, pszName, cchName);
     370        pDev->szPulseName[cchName] = '\0';
     371
     372        pDev->Core.enmUsage           = enmDir;
     373        pDev->Core.enmType            = RTStrIStr(pszDesc, "built-in") != NULL
     374                                      ? PDMAUDIODEVICETYPE_BUILTIN : PDMAUDIODEVICETYPE_UNKNOWN;
     375        pDev->Core.fFlags             = RTStrCmp(pszName, pszDefaultName) == 0
     376                                      ? PDMAUDIOHOSTDEV_F_DEFAULT  : PDMAUDIOHOSTDEV_F_NONE;
     377        pDev->Core.cMaxInputChannels  = cChannelsInput;
     378        pDev->Core.cMaxOutputChannels = cChannelsOutput;
     379        RTStrCopy(pDev->Core.szName, sizeof(pDev->Core.szName),
     380                  pszDesc && *pszDesc ? pszDesc : pszName);
     381
     382        PDMAudioHostEnumAppend(pCbCtx->pDeviceEnum, &pDev->Core);
     383    }
     384    else
     385        pCbCtx->rcEnum = VERR_NO_MEMORY;
     386}
     387
     388
     389/**
    340390 * Enumeration callback - source info.
    341391 *
     
    357407    if (eol == 0 && pInfo != NULL)
    358408    {
    359         LogRel2(("PulseAudio: Using input source '%s'\n", pInfo->name));
    360         /** @todo Store sources + channel mapping in callback context as soon as we have surround support. */
    361         pCbCtx->cDevIn++;
     409        if (pCbCtx->pDeviceEnum)
     410            drvHostAudioPaEnumAddDevice(pCbCtx, PDMAUDIODIR_IN, pInfo->name, pInfo->description,
     411                                        pInfo->sample_spec.channels, 0 /*cChannelsOutput*/, pCbCtx->pszDefaultSource);
     412        else
     413        {
     414            LogRel2(("PulseAudio: Using input source '%s'\n", pInfo->name));
     415            /** @todo Store sources + channel mapping in callback context as soon as we have surround support. */
     416        }
     417    }
     418    else if (eol == 1 && !pInfo && pCbCtx->rcEnum == VERR_AUDIO_ENUMERATION_FAILED)
    362419        pCbCtx->rcEnum = VINF_SUCCESS;
    363     }
    364420
    365421    /* Wake up the calling thread when done: */
     
    389445    if (eol == 0 && pInfo != NULL)
    390446    {
    391         LogRel2(("PulseAudio: Using output sink '%s'\n", pInfo->name));
    392         /** @todo Store sinks + channel mapping in callback context as soon as we have surround support. */
    393         pCbCtx->cDevOut++;
     447        if (pCbCtx->pDeviceEnum)
     448            drvHostAudioPaEnumAddDevice(pCbCtx, PDMAUDIODIR_OUT, pInfo->name, pInfo->description,
     449                                        0 /*cChannelsInput*/, pInfo->sample_spec.channels, pCbCtx->pszDefaultSink);
     450        else
     451        {
     452            LogRel2(("PulseAudio: Using output sink '%s'\n", pInfo->name));
     453            /** @todo Store sinks + channel mapping in callback context as soon as we have surround support. */
     454        }
     455    }
     456    else if (eol == 1 && !pInfo && pCbCtx->rcEnum == VERR_AUDIO_ENUMERATION_FAILED)
    394457        pCbCtx->rcEnum = VINF_SUCCESS;
    395     }
    396458
    397459    /* Wake up the calling thread when done: */
     
    420482                 pInfo->sample_spec.format, pInfo->sample_spec.rate, pInfo->sample_spec.channels));
    421483
     484        Assert(!pCbCtx->pszDefaultSink);
     485        Assert(!pCbCtx->pszDefaultSource);
     486        Assert(pCbCtx->rcEnum == VERR_AUDIO_ENUMERATION_FAILED);
    422487        pCbCtx->rcEnum = VINF_SUCCESS;
    423488
     
    446511 * @note Called with the PA main loop locked.
    447512 */
    448 static int drvHostAudioPaEnumerate(PDRVHOSTPULSEAUDIO pThis, PPDMAUDIOBACKENDCFG pCfg, uint32_t fEnum)
    449 {
    450     PULSEAUDIOENUMCBCTX CbCtx = { pThis, pThis->pMainLoop, fEnum, VERR_AUDIO_BACKEND_INIT_FAILED, 0, 0, NULL, NULL };
     513static int drvHostAudioPaEnumerate(PDRVHOSTPULSEAUDIO pThis, PPDMAUDIOBACKENDCFG pCfg,
     514                                   uint32_t fEnum, PPDMAUDIOHOSTENUM pDeviceEnum)
     515{
     516    PULSEAUDIOENUMCBCTX CbCtx = { pThis->pMainLoop, fEnum, VERR_AUDIO_ENUMERATION_FAILED, NULL, NULL, pDeviceEnum };
    451517    bool const          fLog  = (fEnum & PULSEAUDIOENUMCBFLAGS_LOG);
    452518    int                 rc;
     
    457523     */
    458524    LogRel(("PulseAudio: Retrieving server information ...\n"));
    459     CbCtx.rcEnum = VERR_AUDIO_BACKEND_INIT_FAILED;
     525    CbCtx.rcEnum = VERR_AUDIO_ENUMERATION_FAILED;
    460526    pa_operation *paOpServerInfo = pa_context_get_server_info(pThis->pContext, drvHostAudioPaEnumServerCallback, &CbCtx);
    461527    if (paOpServerInfo)
     
    478544     * Get info about the playback sink.
    479545     */
    480     if (CbCtx.pszDefaultSink)
    481     {
    482         if (fLog)
    483             LogRel2(("PulseAudio: Default output sink is '%s'\n", CbCtx.pszDefaultSink));
    484         CbCtx.rcEnum = VERR_AUDIO_BACKEND_INIT_FAILED;
    485         rc = drvHostAudioPaWaitFor(pThis, pa_context_get_sink_info_by_name(pThis->pContext, CbCtx.pszDefaultSink,
    486                                                                            drvHostAudioPaEnumSinkCallback, &CbCtx));
     546    if (fLog && CbCtx.pszDefaultSink)
     547        LogRel2(("PulseAudio: Default output sink is '%s'\n", CbCtx.pszDefaultSink));
     548    else if (fLog)
     549        LogRel2(("PulseAudio: No default output sink found\n"));
     550
     551    if (CbCtx.pszDefaultSink || pDeviceEnum)
     552    {
     553        CbCtx.rcEnum = VERR_AUDIO_ENUMERATION_FAILED;
     554        if (pDeviceEnum)
     555            rc = drvHostAudioPaWaitFor(pThis,
     556                                       pa_context_get_sink_info_list(pThis->pContext, drvHostAudioPaEnumSinkCallback, &CbCtx));
     557        else
     558            rc = drvHostAudioPaWaitFor(pThis, pa_context_get_sink_info_by_name(pThis->pContext, CbCtx.pszDefaultSink,
     559                                                                               drvHostAudioPaEnumSinkCallback, &CbCtx));
    487560        if (RT_SUCCESS(rc))
    488561            rc = CbCtx.rcEnum;
    489         if (fLog)
    490         {
    491             if (RT_SUCCESS(rc))
    492                 LogRel2(("PulseAudio: Found %RU8 host playback device(s)\n",  CbCtx.cDevOut));
    493             else
    494                 LogRel(("PulseAudio: Error enumerating properties for default output sink '%s': %Rrc\n",
    495                         CbCtx.pszDefaultSink, rc));
    496         }
    497     }
    498     else if (fLog)
    499         LogRel2(("PulseAudio: No default output sink found\n"));
     562        if (fLog && RT_FAILURE(rc))
     563            LogRel(("PulseAudio: Error enumerating properties for default output sink '%s': %Rrc\n",
     564                    CbCtx.pszDefaultSink, rc));
     565    }
    500566
    501567    /*
    502568     * Get info about the recording source.
    503569     */
    504     if (CbCtx.pszDefaultSource)
    505     {
    506         if (fLog)
    507             LogRel2(("PulseAudio: Default input source is '%s'\n", CbCtx.pszDefaultSource));
    508         CbCtx.rcEnum = VERR_AUDIO_BACKEND_INIT_FAILED;
    509         int rc2 = drvHostAudioPaWaitFor(pThis, pa_context_get_source_info_by_name(pThis->pContext, CbCtx.pszDefaultSource,
     570    if (fLog && CbCtx.pszDefaultSource)
     571        LogRel2(("PulseAudio: Default input source is '%s'\n", CbCtx.pszDefaultSource));
     572    else if (fLog)
     573        LogRel2(("PulseAudio: No default input source found\n"));
     574    if (CbCtx.pszDefaultSource || pDeviceEnum)
     575    {
     576        CbCtx.rcEnum = VERR_AUDIO_ENUMERATION_FAILED;
     577        int rc2;
     578        if (pDeviceEnum)
     579            rc2 = drvHostAudioPaWaitFor(pThis, pa_context_get_source_info_list(pThis->pContext,
     580                                                                               drvHostAudioPaEnumSourceCallback, &CbCtx));
     581        else
     582            rc2 = drvHostAudioPaWaitFor(pThis, pa_context_get_source_info_by_name(pThis->pContext, CbCtx.pszDefaultSource,
    510583                                                                                  drvHostAudioPaEnumSourceCallback, &CbCtx));
    511584        if (RT_SUCCESS(rc2))
    512585            rc2 = CbCtx.rcEnum;
    513         if (fLog)
    514         {
    515             if (RT_SUCCESS(rc2))
    516                 LogRel2(("PulseAudio: Found %RU8 host capturing device(s)\n", CbCtx.cDevIn));
    517             else
    518                 LogRel(("PulseAudio: Error enumerating properties for default input source '%s': %Rrc\n",
    519                         CbCtx.pszDefaultSource, rc));
    520         }
     586        if (fLog && RT_FAILURE(rc2))
     587            LogRel(("PulseAudio: Error enumerating properties for default input source '%s': %Rrc\n",
     588                    CbCtx.pszDefaultSource, rc));
    521589        if (RT_SUCCESS(rc))
    522590            rc = rc2;
    523591    }
    524     else if (fLog)
    525         LogRel2(("PulseAudio: No default input source found\n"));
    526592
    527593    /** @todo r=bird: WTF are we making all this effort here w/o actually
    528      *        updating niether the backend configuration structure nor pThis?
    529      *        Sigh^3! */
     594     *        updating neither the backend configuration structure nor pThis?
     595     *        Sigh^3!
     596     *
     597     * update: I've reused this code for actual device enumeration now, so
     598     *         it's not 99.5% useless anymore, but I'm still puzzled at why it's
     599     *         required for pfnGetConfig... */
    530600    RT_NOREF(pCfg);
    531601
     
    556626    /* Refine it or something (currently only some LogRel2 stuff): */
    557627    pa_threaded_mainloop_lock(pThis->pMainLoop);
    558     int rc = drvHostAudioPaEnumerate(pThis, pBackendCfg, PULSEAUDIOENUMCBFLAGS_LOG /* fEnum */);
     628    int rc = drvHostAudioPaEnumerate(pThis, pBackendCfg, PULSEAUDIOENUMCBFLAGS_LOG, NULL /*pDeviceEnum*/);
    559629    pa_threaded_mainloop_unlock(pThis->pMainLoop);
    560630    return rc;
     
    563633
    564634/**
     635 * @interface_method_impl{PDMIHOSTAUDIO,pfnGetDevices}
     636 */
     637static DECLCALLBACK(int) drvHostAudioPaHA_GetDevices(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHOSTENUM pDeviceEnum)
     638{
     639    PDRVHOSTPULSEAUDIO pThis = RT_FROM_MEMBER(pInterface, DRVHOSTPULSEAUDIO, IHostAudio);
     640    AssertPtrReturn(pDeviceEnum, VERR_INVALID_POINTER);
     641    PDMAudioHostEnumInit(pDeviceEnum);
     642
     643    /* Refine it or something (currently only some LogRel2 stuff): */
     644    pa_threaded_mainloop_lock(pThis->pMainLoop);
     645    int rc = drvHostAudioPaEnumerate(pThis, NULL /*pCfg*/, PULSEAUDIOENUMCBFLAGS_NONE, pDeviceEnum);
     646    pa_threaded_mainloop_unlock(pThis->pMainLoop);
     647    return rc;
     648}
     649
     650
     651
     652/**
    565653 * @interface_method_impl{PDMIHOSTAUDIO,pfnGetStatus}
    566654 */
    567655static DECLCALLBACK(PDMAUDIOBACKENDSTS) drvHostAudioPaHA_GetStatus(PPDMIHOSTAUDIO pInterface, PDMAUDIODIR enmDir)
    568656{
    569     RT_NOREF(enmDir);
    570     AssertPtrReturn(pInterface, PDMAUDIOBACKENDSTS_UNKNOWN);
    571 
     657    RT_NOREF(pInterface, enmDir);
    572658    return PDMAUDIOBACKENDSTS_RUNNING;
    573659}
     
    15201606    /* IHostAudio */
    15211607    pThis->IHostAudio.pfnGetConfig          = drvHostAudioPaHA_GetConfig;
    1522     pThis->IHostAudio.pfnGetDevices         = NULL;
     1608    pThis->IHostAudio.pfnGetDevices         = drvHostAudioPaHA_GetDevices;
    15231609    pThis->IHostAudio.pfnGetStatus          = drvHostAudioPaHA_GetStatus;
    15241610    pThis->IHostAudio.pfnStreamCreate       = drvHostAudioPaHA_StreamCreate;
  • trunk/src/VBox/Devices/Audio/DrvHostAudioPulseAudioStubs.cpp

    r88226 r88478  
    7777                (pa_context *c, const char *name, pa_sink_info_cb_t cb, void *userdata),
    7878                (c, name, cb, userdata))
     79PROXY_STUB     (pa_context_get_sink_info_list, pa_operation *,
     80                (pa_context *c, pa_sink_info_cb_t cb, void *userdata),
     81                (c, cb, userdata))
    7982PROXY_STUB     (pa_context_get_source_info_by_name, pa_operation*,
    8083                (pa_context *c, const char *name, pa_source_info_cb_t cb, void *userdata),
    8184                (c, name, cb, userdata))
     85PROXY_STUB     (pa_context_get_source_info_list, pa_operation *,
     86                (pa_context *c, pa_source_info_cb_t cb, void *userdata),
     87                (c, cb, userdata))
    8288PROXY_STUB     (pa_context_get_state, pa_context_state_t,
    8389                (pa_context *c),
     
    257263    FUNC_ENTRY(pa_context_get_server_info),
    258264    FUNC_ENTRY(pa_context_get_sink_info_by_name),
     265    FUNC_ENTRY(pa_context_get_sink_info_list),
    259266    FUNC_ENTRY(pa_context_get_source_info_by_name),
     267    FUNC_ENTRY(pa_context_get_source_info_list),
    260268    FUNC_ENTRY(pa_context_get_state),
    261269    FUNC_ENTRY(pa_context_unref),
  • trunk/src/VBox/Devices/Audio/DrvHostAudioPulseAudioStubsMangling.h

    r88226 r88478  
    3434#define pa_context_get_server_info              PULSE_MANGLER(pa_context_get_server_info)
    3535#define pa_context_get_sink_info_by_name        PULSE_MANGLER(pa_context_get_sink_info_by_name)
     36#define pa_context_get_sink_info_list           PULSE_MANGLER(pa_context_get_sink_info_list)
    3637#define pa_context_get_source_info_by_name      PULSE_MANGLER(pa_context_get_source_info_by_name)
     38#define pa_context_get_source_info_list         PULSE_MANGLER(pa_context_get_source_info_list)
    3739#define pa_context_get_state                    PULSE_MANGLER(pa_context_get_state)
    3840#define pa_context_unref                        PULSE_MANGLER(pa_context_unref)
Note: See TracChangeset for help on using the changeset viewer.

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