VirtualBox

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


Ignore:
Timestamp:
Nov 18, 2015 10:22:54 AM (9 years ago)
Author:
vboxsync
Message:

Audio: DrvHostDSound.cpp: Initial implementation of threaded audio notification support (output only, not enabled by default yet).

File:
1 edited

Legend:

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

    r58378 r58733  
    6767typedef FNDIRECTSOUNDCAPTUREENUMERATEW *PFNDIRECTSOUNDCAPTUREENUMERATEW;
    6868
     69#ifdef VBOX_WITH_AUDIO_CALLBACKS
     70# define VBOX_DSOUND_MAX_EVENTS 3
     71
     72typedef enum DSOUNDEVENT
     73{
     74    DSOUNDEVENT_NOTIFY = 0,
     75    DSOUNDEVENT_INPUT,
     76    DSOUNDEVENT_OUTPUT,
     77 } DSOUNDEVENT;
     78#endif /* VBOX_WITH_AUDIO_CALLBACKS */
     79
    6980typedef struct DSOUNDHOSTCFG
    7081{
     
    7687    LPCGUID pGuidCapture;
    7788} DSOUNDHOSTCFG, *PDSOUNDHOSTCFG;
     89
     90typedef struct DSOUNDSTREAMOUT
     91{
     92    PDMAUDIOHSTSTRMOUT   strmOut; /* Always must come first! */
     93    LPDIRECTSOUND8       pDS;
     94    LPDIRECTSOUNDBUFFER8 pDSB;
     95    DWORD                cbPlayWritePos;
     96    DWORD                csPlaybackBufferSize;
     97    bool                 fRestartPlayback;
     98    PDMAUDIOSTREAMCFG    streamCfg;
     99} DSOUNDSTREAMOUT, *PDSOUNDSTREAMOUT;
     100
     101typedef struct DSOUNDSTREAMIN
     102{
     103    PDMAUDIOHSTSTRMIN           strmIn; /* Always must come first! */
     104    LPDIRECTSOUNDCAPTURE8       pDSC;
     105    LPDIRECTSOUNDCAPTUREBUFFER8 pDSCB;
     106    DWORD                       csCaptureReadPos;
     107    DWORD                       csCaptureBufferSize;
     108    HRESULT                     hrLastCaptureIn;
     109    PDMAUDIORECSOURCE           enmRecSource;
     110    PDMAUDIOSTREAMCFG           streamCfg;
     111} DSOUNDSTREAMIN, *PDSOUNDSTREAMIN;
    78112
    79113typedef struct DRVHOSTDSOUND
     
    89123    /** DirectSound configuration options. */
    90124    DSOUNDHOSTCFG cfg;
     125#ifdef VBOX_WITH_AUDIO_CALLBACKS
     126    /** Stopped indicator. */
     127    bool          fStopped;
     128    /** Shutdown indicator. */
     129    bool          fShutdown;
     130    /** Notification thread. */
     131    RTTHREAD      Thread;
     132    /** Array of events to wait for in notification thread. */
     133    HANDLE        aEvents[VBOX_DSOUND_MAX_EVENTS];
     134    /** Number of events to wait for in notification thread.
     135     *  Must not exceed VBOX_DSOUND_MAX_EVENTS. */
     136    uint8_t       cEvents;
     137    PDSOUNDSTREAMIN pStrmIn;
     138    PDSOUNDSTREAMOUT pStrmOut;
     139#endif
    91140} DRVHOSTDSOUND, *PDRVHOSTDSOUND;
    92 
    93 typedef struct DSOUNDSTREAMOUT
    94 {
    95     PDMAUDIOHSTSTRMOUT   strmOut; /* Always must come first! */
    96     LPDIRECTSOUND8       pDS;
    97     LPDIRECTSOUNDBUFFER8 pDSB;
    98     DWORD                cbPlayWritePos;
    99     DWORD                csPlaybackBufferSize;
    100     bool                 fRestartPlayback;
    101     PDMAUDIOSTREAMCFG    streamCfg;
    102 } DSOUNDSTREAMOUT, *PDSOUNDSTREAMOUT;
    103 
    104 typedef struct DSOUNDSTREAMIN
    105 {
    106     PDMAUDIOHSTSTRMIN           strmIn; /* Always must come first! */
    107     LPDIRECTSOUNDCAPTURE8       pDSC;
    108     LPDIRECTSOUNDCAPTUREBUFFER8 pDSCB;
    109     DWORD                       csCaptureReadPos;
    110     DWORD                       csCaptureBufferSize;
    111     HRESULT                     hrLastCaptureIn;
    112     PDMAUDIORECSOURCE           enmRecSource;
    113     PDMAUDIOSTREAMCFG           streamCfg;
    114 } DSOUNDSTREAMIN, *PDSOUNDSTREAMIN;
    115141
    116142/**
     
    135161
    136162static void dsoundDevRemove(PDSOUNDDEV pDev);
     163#ifdef VBOX_WITH_AUDIO_CALLBACKS
     164static int dsoundNotifyThread(PDRVHOSTDSOUND pThis, bool fShutdown);
     165#endif
    137166
    138167static DWORD dsoundRingDistance(DWORD offEnd, DWORD offBegin, DWORD cSize)
     
    376405}
    377406
    378 static void directSoundPlayClose(PDSOUNDSTREAMOUT pDSoundStrmOut)
    379 {
     407static void directSoundPlayClose(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMOUT pDSoundStrmOut)
     408{
     409    AssertPtrReturnVoid(pThis);
     410    AssertPtrReturnVoid(pDSoundStrmOut);
     411
    380412    DSLOG(("DSound: Closing playback stream %p, buffer %p\n", pDSoundStrmOut, pDSoundStrmOut->pDSB));
    381413
     
    386418            DSLOGREL(("DSound: Stop playback stream %p when closing %Rhrc\n", pDSoundStrmOut, hr));
    387419
     420#ifdef VBOX_WITH_AUDIO_CALLBACKS
     421        if (pThis->aEvents[DSOUNDEVENT_OUTPUT] != NULL)
     422        {
     423            CloseHandle(pThis->aEvents[DSOUNDEVENT_OUTPUT]);
     424            pThis->aEvents[DSOUNDEVENT_OUTPUT] = NULL;
     425
     426            if (pThis->cEvents)
     427                pThis->cEvents--;
     428
     429            pThis->pStrmOut = NULL;
     430        }
     431#endif
    388432        IDirectSoundBuffer8_Release(pDSoundStrmOut->pDSB);
    389433        pDSoundStrmOut->pDSB = NULL;
     
    410454        /* Should not happen but be forgiving. */
    411455        DSLOGREL(("DSound: DirectSoundBuffer already exists\n"));
    412         directSoundPlayClose(pDSoundStrmOut);
     456        directSoundPlayClose(pThis, pDSoundStrmOut);
    413457    }
    414458
     
    425469    {
    426470        LPDIRECTSOUNDBUFFER pDSB = NULL;
     471
    427472        DSBUFFERDESC bd;
    428473        RT_ZERO(bd);
    429         bd.dwSize = sizeof(bd);
    430         bd.lpwfxFormat = &wfx;
    431         bd.dwFlags = DSBCAPS_GLOBALFOCUS | DSBCAPS_GETCURRENTPOSITION2;
     474        bd.dwSize        = sizeof(bd);
     475        bd.lpwfxFormat   = &wfx;
     476        bd.dwFlags       = DSBCAPS_GLOBALFOCUS | DSBCAPS_GETCURRENTPOSITION2;
     477#ifdef VBOX_WITH_AUDIO_CALLBACKS
     478        bd.dwFlags      |= DSBCAPS_CTRLPOSITIONNOTIFY;
     479#endif
    432480        bd.dwBufferBytes = pThis->cfg.cbBufferOut;
    433         hr = IDirectSound8_CreateSoundBuffer(pDSoundStrmOut->pDS,
    434                                             &bd, &pDSB, NULL);
     481
     482        hr = IDirectSound8_CreateSoundBuffer(pDSoundStrmOut->pDS, &bd, &pDSB, NULL);
    435483        if (FAILED(hr))
    436484        {
     
    439487        }
    440488
    441         /* "Upgrade" to IDirectSoundBuffer8 intarface. */
    442         hr = IDirectSoundBuffer_QueryInterface(pDSB, IID_IDirectSoundBuffer8, (void **)&pDSoundStrmOut->pDSB);
    443         pDSB->Release();
     489        /* "Upgrade" to IDirectSoundBuffer8 interface. */
     490        hr = IDirectSoundBuffer_QueryInterface(pDSB, IID_IDirectSoundBuffer8, (LPVOID *)&pDSoundStrmOut->pDSB);
     491        IDirectSoundBuffer_Release(pDSB);
    444492        if (FAILED(hr))
    445493        {
     
    502550        DSLOG(("DSound: csPlaybackBufferSize=%RU32\n", pDSoundStrmOut->csPlaybackBufferSize));
    503551
     552#ifdef VBOX_WITH_AUDIO_CALLBACKS
     553        /*
     554         * Install notification.
     555         */
     556        pThis->aEvents[DSOUNDEVENT_OUTPUT] = CreateEvent(NULL /* Security attribute */,
     557                                                         FALSE /* bManualReset */, FALSE /* bInitialState */,
     558                                                         NULL /* lpName */);
     559        if (pThis->aEvents[DSOUNDEVENT_OUTPUT] == NULL)
     560        {
     561            hr = HRESULT_FROM_WIN32(GetLastError());
     562            DSLOGREL(("DSound: CreateEvent for output failed with hr=%Rhrc\n", hr));
     563            break;
     564        }
     565
     566        LPDIRECTSOUNDNOTIFY8 pNotify;
     567        hr = IDirectSoundNotify_QueryInterface(pDSoundStrmOut->pDSB, IID_IDirectSoundNotify8, (LPVOID *)&pNotify);
     568        if (SUCCEEDED(hr))
     569        {
     570            DSBPOSITIONNOTIFY dsBufPosNotify;
     571            RT_ZERO(dsBufPosNotify);
     572            dsBufPosNotify.dwOffset     = DSBPN_OFFSETSTOP;
     573            dsBufPosNotify.hEventNotify = pThis->aEvents[DSOUNDEVENT_OUTPUT];
     574
     575            hr = IDirectSoundNotify_SetNotificationPositions(pNotify, 1 /* Count */, &dsBufPosNotify);
     576            if (FAILED(hr))
     577                DSLOGREL(("DSound: IDirectSoundNotify_SetNotificationPositions failed with hr=%Rhrc\n", hr));
     578
     579            IDirectSoundNotify_Release(pNotify);
     580        }
     581        else
     582            DSLOGREL(("DSound: IDirectSoundNotify_QueryInterface failed with hr=%Rhrc\n", hr));
     583
     584        if (FAILED(hr))
     585            break;
     586
     587        pThis->pStrmOut = pDSoundStrmOut;
     588
     589        Assert(pThis->cEvents < VBOX_DSOUND_MAX_EVENTS);
     590        pThis->cEvents++;
     591
     592        /* Let the thread know. */
     593        dsoundNotifyThread(pThis, false /* fShutdown */);
     594
     595        /* Trigger the just installed output notification. */
     596        hr = IDirectSoundBuffer8_Play(pDSoundStrmOut->pDSB, 0, 0, 0);
     597
     598#endif /* VBOX_WITH_AUDIO_CALLBACKS */
     599
    504600    } while (0);
    505601
    506602    if (FAILED(hr))
    507         directSoundPlayClose(pDSoundStrmOut);
     603        directSoundPlayClose(pThis, pDSoundStrmOut);
    508604
    509605    return hr;
     
    10711167            if (FAILED(hr))
    10721168            {
    1073                 directSoundPlayClose(pDSoundStrmOut);
     1169                directSoundPlayClose(pThis, pDSoundStrmOut);
    10741170                directSoundPlayOpen(pThis, pDSoundStrmOut);
    10751171
     
    11311227            hr = directSoundPlayRestore(pDSB);
    11321228            if (SUCCEEDED(hr))
    1133             {
    11341229                hr = IDirectSoundBuffer8_GetCurrentPosition(pDSB, &cbPlayPos, NULL);
    1135             }
    11361230        }
    11371231
     
    12411335    PDSOUNDSTREAMOUT pDSoundStrmOut = (PDSOUNDSTREAMOUT)pHstStrmOut;
    12421336
    1243     directSoundPlayClose(pDSoundStrmOut);
    1244 
    1245     pDSoundStrmOut->cbPlayWritePos = 0;
    1246     pDSoundStrmOut->fRestartPlayback = true;
     1337    directSoundPlayClose(pThis, pDSoundStrmOut);
     1338
     1339    pDSoundStrmOut->cbPlayWritePos       = 0;
     1340    pDSoundStrmOut->fRestartPlayback     = true;
    12471341    pDSoundStrmOut->csPlaybackBufferSize = 0;
     1342
    12481343    RT_ZERO(pDSoundStrmOut->streamCfg);
    12491344
     
    15551650}
    15561651
     1652#ifdef VBOX_WITH_AUDIO_CALLBACKS
     1653static int dsoundNotifyThread(PDRVHOSTDSOUND pThis, bool fShutdown)
     1654{
     1655    AssertPtrReturn(pThis, VERR_INVALID_POINTER);
     1656
     1657    if (fShutdown)
     1658    {
     1659        LogFlowFunc(("Shutting down thread ...\n"));
     1660        pThis->fShutdown = fShutdown;
     1661    }
     1662
     1663    /* Set the notification event so that the thread is being notified. */
     1664    BOOL fRc = SetEvent(pThis->aEvents[DSOUNDEVENT_NOTIFY]);
     1665    Assert(fRc);
     1666
     1667    return VINF_SUCCESS;
     1668}
     1669
     1670static DECLCALLBACK(int) drvHostDSoundThread(RTTHREAD hThreadSelf, void *pvUser)
     1671{
     1672    PDRVHOSTDSOUND pThis = (PDRVHOSTDSOUND)pvUser;
     1673    AssertPtr(pThis);
     1674
     1675    LogFlowFuncEnter();
     1676
     1677    /* Let caller know that we're done initializing, regardless of the result. */
     1678    int rc = RTThreadUserSignal(hThreadSelf);
     1679    AssertRC(rc);
     1680
     1681    HRESULT hr;
     1682
     1683    do
     1684    {
     1685        HANDLE aEvents[VBOX_DSOUND_MAX_EVENTS];
     1686        DWORD  cEvents = 0;
     1687        for (uint8_t i = 0; i < VBOX_DSOUND_MAX_EVENTS; i++)
     1688        {
     1689            if (pThis->aEvents[i])
     1690                aEvents[cEvents++] = pThis->aEvents[i];
     1691        }
     1692        Assert(cEvents);
     1693
     1694        LogFlowFunc(("Waiting: cEvents=%ld\n", cEvents));
     1695
     1696        DWORD dwObj = WaitForMultipleObjects(cEvents, aEvents, FALSE /* bWaitAll */, INFINITE);
     1697        switch (dwObj)
     1698        {
     1699            case WAIT_FAILED:
     1700            {
     1701                rc = VERR_CANCELLED;
     1702                break;
     1703            }
     1704
     1705            case WAIT_TIMEOUT:
     1706            {
     1707                rc = VERR_TIMEOUT;
     1708                break;
     1709            }
     1710
     1711            default:
     1712            {
     1713                dwObj = WAIT_OBJECT_0 + cEvents - 1;
     1714                if (aEvents[dwObj] == pThis->aEvents[DSOUNDEVENT_NOTIFY])
     1715                {
     1716                    LogFlowFunc(("Notify\n"));
     1717                }
     1718                else if (aEvents[dwObj] == pThis->aEvents[DSOUNDEVENT_INPUT])
     1719                {
     1720
     1721                }
     1722                else if (aEvents[dwObj] == pThis->aEvents[DSOUNDEVENT_OUTPUT])
     1723                {
     1724                    DWORD cbPlayPos;
     1725                    hr = IDirectSoundCaptureBuffer8_GetCurrentPosition(pThis->pStrmOut->pDSB, NULL, &cbPlayPos);
     1726                    LogFlowFunc(("Output: hr=%Rhrc, dwPlayPos=%ld\n", hr, cbPlayPos));
     1727                }
     1728                break;
     1729            }
     1730        }
     1731
     1732        if (pThis->fShutdown)
     1733            break;
     1734
     1735    } while (RT_SUCCESS(rc));
     1736
     1737    pThis->fStopped = true;
     1738
     1739    LogFlowFunc(("Exited with fShutdown=%RTbool, rc=%Rrc\n", pThis->fShutdown, rc));
     1740    return rc;
     1741}
     1742#endif /* VBOX_WITH_AUDIO_CALLBACKS */
     1743
    15571744static DECLCALLBACK(void) drvHostDSoundShutdown(PPDMIHOSTAUDIO pInterface)
    15581745{
    1559     NOREF(pInterface);
     1746    PDRVHOSTDSOUND pThis = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface);
     1747
     1748    LogFlowFuncEnter();
     1749
     1750#ifdef VBOX_WITH_AUDIO_CALLBACKS
     1751    int rc = dsoundNotifyThread(pThis, true /* fShutdown */);
     1752    AssertRC(rc);
     1753
     1754    int rcThread;
     1755    rc = RTThreadWait(pThis->Thread,  15 * 1000 /* 15s timeout */, &rcThread);
     1756    LogFlowFunc(("rc=%Rrc, rcThread=%Rrc\n", rc, rcThread));
     1757
     1758    Assert(pThis->fStopped);
     1759
     1760    if (pThis->aEvents[DSOUNDEVENT_NOTIFY])
     1761    {
     1762        CloseHandle(pThis->aEvents[DSOUNDEVENT_NOTIFY]);
     1763        pThis->aEvents[DSOUNDEVENT_NOTIFY] = NULL;
     1764    }
     1765#endif
     1766
     1767    LogFlowFuncLeave();
    15601768}
    15611769
     
    15651773
    15661774    LogFlowFuncEnter();
     1775
     1776    int rc;
    15671777
    15681778    /* Verify that IDirectSound is available. */
     
    15711781                                  IID_IDirectSound, (void **)&pDirectSound);
    15721782    if (SUCCEEDED(hr))
     1783    {
    15731784        IDirectSound_Release(pDirectSound);
     1785
     1786#ifdef VBOX_WITH_AUDIO_CALLBACKS
     1787        /* Create notification event. */
     1788        pThis->aEvents[DSOUNDEVENT_NOTIFY] = CreateEvent(NULL /* Security attribute */,
     1789                                                         FALSE /* bManualReset */, FALSE /* bInitialState */,
     1790                                                         NULL /* lpName */);
     1791        Assert(pThis->aEvents[DSOUNDEVENT_NOTIFY] != NULL);
     1792
     1793        /* Start notification thread. */
     1794        rc = RTThreadCreate(&pThis->Thread, drvHostDSoundThread,
     1795                            pThis /*pvUser*/, 0 /*cbStack*/,
     1796                            RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "dSoundNtfy");
     1797        if (RT_SUCCESS(rc))
     1798        {
     1799            /* Wait for the thread to initialize. */
     1800            rc = RTThreadUserWait(pThis->Thread, RT_MS_1MIN);
     1801            if (RT_FAILURE(rc))
     1802                DSLOGREL(("DSound: Waiting for thread to initialize failed with rc=%Rrc\n", rc));
     1803        }
     1804        else
     1805            DSLOGREL(("DSound: Creating thread failed with rc=%Rrc\n", rc));
     1806#endif
     1807    }
    15741808    else
     1809    {
    15751810        DSLOGREL(("DSound: DirectSound not available %Rhrc\n", hr));
    1576 
    1577     int rc = SUCCEEDED(hr) ? VINF_SUCCESS: VERR_NOT_SUPPORTED;
     1811        rc = VERR_NOT_SUPPORTED;
     1812    }
    15781813
    15791814    LogFlowFuncLeaveRC(rc);
     
    16731908    RTListInit(&pThis->lstDevInput);
    16741909    RTListInit(&pThis->lstDevOutput);
     1910
     1911#ifdef VBOX_WITH_AUDIO_CALLBACKS
     1912    pThis->fStopped  = false;
     1913    pThis->fShutdown = false;
     1914
     1915    RT_ZERO(pThis->aEvents);
     1916    pThis->cEvents = 0;
     1917#endif
    16751918
    16761919    /*
     
    16981941    "DirectSound Audio host driver",
    16991942    /* fFlags */
    1700      PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
     1943    PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
    17011944    /* fClass. */
    17021945    PDM_DRVREG_CLASS_AUDIO,
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