VirtualBox

Changeset 89165 in vbox


Ignore:
Timestamp:
May 19, 2021 1:21:08 PM (4 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
144506
Message:

DrvHostAudioCoreAudio: Re-introducing the worker thread, but now we've only got one for each driver instance instead of per stream. bugref:9890

File:
1 edited

Legend:

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

    r89133 r89165  
    4747
    4848#include <iprt/uuid.h>
     49#include <iprt/timer.h>
    4950
    5051#include <CoreAudio/CoreAudio.h>
     
    5354#include <AudioToolbox/AudioConverter.h>
    5455#include <AudioToolbox/AudioToolbox.h>
    55 
    56 
    57 
    58 /* Enables utilizing the Core Audio converter unit for converting
    59  * input / output from/to our requested formats. That might be more
    60  * performant than using our own routines later down the road. */
    61 /** @todo Needs more investigation and testing first before enabling. */
    62 //# define VBOX_WITH_AUDIO_CA_CONVERTER
    63 
    64 /** @todo
    65  * - Maybe make sure the threads are immediately stopped if playing/recording stops.
    66  */
    6756
    6857
     
    7463/** The minimum number of queue buffers. */
    7564#define COREAUDIO_MIN_BUFFERS       4
     65
     66/** Enables the worker thread.
     67 * This saves CoreAudio from creating an additional thread upon queue
     68 * creation.  (It does not help with the slow AudioQueueDispose fun.)  */
     69#define CORE_AUDIO_WITH_WORKER_THREAD
     70#if 0
     71/** Enables the AudioQueueDispose breakpoint timer (debugging help). */
     72# define CORE_AUDIO_WITH_BREAKPOINT_TIMER
     73#endif
     74
     75/* Enables utilizing the Core Audio converter unit for converting
     76 * input / output from/to our requested formats. That might be more
     77 * performant than using our own routines later down the road. */
     78/** @todo Needs more investigation and testing first before enabling. */
     79//# define VBOX_WITH_AUDIO_CA_CONVERTER
    7680
    7781
     
    284288    /** Indicates whether we've registered default output device change listener. */
    285289    bool                    fRegisteredDefaultOutputListener;
     290
     291#ifdef CORE_AUDIO_WITH_WORKER_THREAD
     292    /** @name Worker Thread For Queue callbacks and stuff.
     293     * @{ */
     294    /** The worker thread. */
     295    RTTHREAD                hThread;
     296    /** The runloop of the worker thread. */
     297    CFRunLoopRef            hThreadRunLoop;
     298    /** The message port we use to talk to the thread.
     299     * @note While we don't currently use the port, it is necessary to prevent
     300     *       the thread from spinning or stopping prematurely because of
     301     *       CFRunLoopRunInMode returning kCFRunLoopRunFinished. */
     302    CFMachPortRef           hThreadPort;
     303    /** Runloop source for hThreadPort. */
     304    CFRunLoopSourceRef      hThreadPortSrc;
     305    /** @} */
     306#endif
     307
    286308    /** Critical section to serialize access. */
    287309    RTCRITSECT              CritSect;
     310#ifdef CORE_AUDIO_WITH_BREAKPOINT_TIMER
     311    /** Timder for debugging AudioQueueDispose slowness. */
     312    RTTIMERLR               hBreakpointTimer;
     313#endif
    288314} DRVHOSTCOREAUDIO;
    289315
     
    803829
    804830/*********************************************************************************************************************************
     831*   Worker Thread                                                                                                                *
     832*********************************************************************************************************************************/
     833#ifdef CORE_AUDIO_WITH_WORKER_THREAD
     834
     835/**
     836 * Message handling callback for CFMachPort.
     837 */
     838static void drvHostAudioCaThreadPortCallback(CFMachPortRef hPort, void *pvMsg, CFIndex cbMsg, void *pvUser)
     839{
     840    RT_NOREF(hPort, pvMsg, cbMsg, pvUser);
     841    LogFunc(("hPort=%p pvMsg=%p cbMsg=%#x pvUser=%p\n", hPort, pvMsg, cbMsg, pvUser));
     842}
     843
     844
     845/**
     846 * @callback_method_impl{FNRTTHREAD, Worker thread for buffer callbacks.}
     847 */
     848static DECLCALLBACK(int) drvHostAudioCaThread(RTTHREAD hThreadSelf, void *pvUser)
     849{
     850    PDRVHOSTCOREAUDIO pThis = (PDRVHOSTCOREAUDIO)pvUser;
     851
     852    /*
     853     * Get the runloop, add the mach port to it and signal the constructor thread that we're ready.
     854     */
     855    pThis->hThreadRunLoop = CFRunLoopGetCurrent();
     856    CFRetain(pThis->hThreadRunLoop);
     857
     858    CFRunLoopAddSource(pThis->hThreadRunLoop, pThis->hThreadPortSrc, kCFRunLoopDefaultMode);
     859
     860    int rc = RTThreadUserSignal(hThreadSelf);
     861    AssertRCReturn(rc, rc);
     862
     863    /*
     864     * Do work.
     865     */
     866    for (;;)
     867    {
     868        SInt32 rcRunLoop = CFRunLoopRunInMode(kCFRunLoopDefaultMode, 30.0, TRUE);
     869        Log8Func(("CFRunLoopRunInMode -> %d\n", rcRunLoop));
     870        Assert(rcRunLoop != kCFRunLoopRunFinished);
     871        if (rcRunLoop != kCFRunLoopRunStopped && rcRunLoop != kCFRunLoopRunFinished)
     872        { /* likely */ }
     873        else
     874            break;
     875    }
     876
     877    /*
     878     * Clean up.
     879     */
     880    CFRunLoopRemoveSource(pThis->hThreadRunLoop, pThis->hThreadPortSrc, kCFRunLoopDefaultMode);
     881    LogFunc(("The thread quits!\n"));
     882    return VINF_SUCCESS;
     883}
     884
     885#endif /* CORE_AUDIO_WITH_WORKER_THREAD */
     886
     887
     888
     889/*********************************************************************************************************************************
    805890*   PDMIHOSTAUDIO                                                                                                                *
    806891*********************************************************************************************************************************/
     
    16151700             * related thread if we don't specify a runloop here.  That's simpler.
    16161701             */
     1702#ifdef CORE_AUDIO_WITH_WORKER_THREAD
     1703            CFRunLoopRef const hRunLoop     = pThis->hThreadRunLoop;
     1704            CFStringRef  const hRunLoopMode = kCFRunLoopDefaultMode;
     1705#else
     1706            CFRunLoopRef const hRunLoop     = NULL;
     1707            CFStringRef  const hRunLoopMode = NULL;
     1708#endif
    16171709            OSStatus orc;
    16181710            if (pCfgReq->enmDir == PDMAUDIODIR_OUT)
    16191711                orc = AudioQueueNewOutput(&pStreamCA->BasicStreamDesc, drvHostAudioCaOutputQueueBufferCallback, pStreamCA,
    1620                                           NULL /*hRunLoop*/, NULL /*pStrRlMode*/, 0 /*fFlags - MBZ*/, &pStreamCA->hAudioQueue);
     1712                                          hRunLoop, hRunLoopMode, 0 /*fFlags - MBZ*/, &pStreamCA->hAudioQueue);
    16211713            else
    16221714                orc = AudioQueueNewInput(&pStreamCA->BasicStreamDesc, drvHostAudioCaInputQueueBufferCallback, pStreamCA,
    1623                                          NULL /*hRunLoop*/, NULL /*pStrRlMode*/, 0 /*fFlags - MBZ*/, &pStreamCA->hAudioQueue);
     1715                                         hRunLoop, hRunLoopMode, 0 /*fFlags - MBZ*/, &pStreamCA->hAudioQueue);
    16241716            if (orc == noErr)
    16251717            {
     
    17461838
    17471839/**
     1840 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamInitAsync}
     1841 */
     1842static DECLCALLBACK(int) drvHostAudioCaHA_StreamInitAsync(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream, bool fDestroyed)
     1843{
     1844    RT_NOREF(pInterface, pStream, fDestroyed);
     1845    return VINF_SUCCESS;
     1846}
     1847
     1848
     1849/**
    17481850 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamDestroy}
    17491851 */
     
    17831885         * Free the queue buffers and the queue.
    17841886         */
     1887#ifdef CORE_AUDIO_WITH_BREAKPOINT_TIMER
     1888        LogRel(("Queue-destruction timer starting...\n"));
     1889        PDRVHOSTCOREAUDIO pThis = RT_FROM_MEMBER(pInterface, DRVHOSTCOREAUDIO, IHostAudio);
     1890        RTTimerLRStart(pThis->hBreakpointTimer, RT_NS_100MS);
     1891        uint64_t nsStart = RTTimeNanoTS();
     1892#endif
     1893
    17851894        if (pStreamCA->paBuffers)
    17861895        {
     
    18061915        }
    18071916
     1917#ifdef CORE_AUDIO_WITH_BREAKPOINT_TIMER
     1918        RTTimerLRStop(pThis->hBreakpointTimer);
     1919        LogRel(("Queue-destruction: %'RU64\n", RTTimeNanoTS() - nsStart));
     1920#endif
     1921
    18081922        /*
    18091923         * Release the device and delete the critsect.
     
    18241938    return VINF_SUCCESS;
    18251939}
     1940
     1941
     1942#ifdef CORE_AUDIO_WITH_BREAKPOINT_TIMER
     1943/** @callback_method_impl{FNRTTIMERLR, For debugging things that takes too long.} */
     1944static DECLCALLBACK(void) drvHostAudioCaBreakpointTimer(RTTIMERLR hTimer, void *pvUser, uint64_t iTick)
     1945{
     1946    LogFlowFunc(("Queue-destruction timeout! iTick=%RU64\n", iTick));
     1947    RT_NOREF(hTimer, pvUser, iTick);
     1948    RTLogFlush(NULL);
     1949    RT_BREAKPOINT();
     1950}
     1951#endif
    18261952
    18271953
     
    26382764    drvHostAudioCaRemoveDefaultDeviceListners(pThis);
    26392765
     2766#ifdef CORE_AUDIO_WITH_WORKER_THREAD
     2767    if (pThis->hThread != NIL_RTTHREAD)
     2768    {
     2769        for (unsigned iLoop = 0; iLoop < 60; iLoop++)
     2770        {
     2771            if (pThis->hThreadRunLoop)
     2772                CFRunLoopStop(pThis->hThreadRunLoop);
     2773            if (iLoop > 10)
     2774                RTThreadPoke(pThis->hThread);
     2775            int rc = RTThreadWait(pThis->hThread, 500 /*ms*/, NULL /*prcThread*/);
     2776            if (RT_SUCCESS(rc))
     2777                break;
     2778            AssertMsgBreak(rc == VERR_TIMEOUT, ("RTThreadWait -> %Rrc\n",rc));
     2779        }
     2780        pThis->hThread = NIL_RTTHREAD;
     2781    }
     2782    if (pThis->hThreadPortSrc)
     2783    {
     2784        CFRelease(pThis->hThreadPortSrc);
     2785        pThis->hThreadPortSrc = NULL;
     2786    }
     2787    if (pThis->hThreadPort)
     2788    {
     2789        CFMachPortInvalidate(pThis->hThreadPort);
     2790        CFRelease(pThis->hThreadPort);
     2791        pThis->hThreadPort = NULL;
     2792    }
     2793    if (pThis->hThreadRunLoop)
     2794    {
     2795        CFRelease(pThis->hThreadRunLoop);
     2796        pThis->hThreadRunLoop = NULL;
     2797    }
     2798#endif
     2799
     2800#ifdef CORE_AUDIO_WITH_BREAKPOINT_TIMER
     2801    if (pThis->hBreakpointTimer != NIL_RTTIMERLR)
     2802    {
     2803        RTTimerLRDestroy(pThis->hBreakpointTimer);
     2804        pThis->hBreakpointTimer = NIL_RTTIMERLR;
     2805    }
     2806#endif
     2807
    26402808    int rc2 = RTCritSectDelete(&pThis->CritSect);
    26412809    AssertRC(rc2);
     
    26602828     */
    26612829    pThis->pDrvIns                   = pDrvIns;
     2830#ifdef CORE_AUDIO_WITH_WORKER_THREAD
     2831    pThis->hThread                   = NIL_RTTHREAD;
     2832#endif
     2833#ifdef CORE_AUDIO_WITH_BREAKPOINT_TIMER
     2834    pThis->hBreakpointTimer          = NIL_RTTIMERLR;
     2835#endif
    26622836    PDMAudioHostEnumInit(&pThis->Devices);
    26632837    /* IBase */
     
    26702844    pThis->IHostAudio.pfnStreamConfigHint           = NULL;
    26712845    pThis->IHostAudio.pfnStreamCreate               = drvHostAudioCaHA_StreamCreate;
    2672     pThis->IHostAudio.pfnStreamInitAsync            = NULL;
     2846    pThis->IHostAudio.pfnStreamInitAsync            = drvHostAudioCaHA_StreamInitAsync;
    26732847    pThis->IHostAudio.pfnStreamDestroy              = drvHostAudioCaHA_StreamDestroy;
    26742848    pThis->IHostAudio.pfnStreamNotifyDeviceChanged  = NULL;
     
    26832857    int rc = RTCritSectInit(&pThis->CritSect);
    26842858    AssertRCReturn(rc, rc);
     2859
     2860#ifdef CORE_AUDIO_WITH_WORKER_THREAD
     2861    /*
     2862     * Create worker thread for running callbacks on.
     2863     */
     2864    CFMachPortContext PortCtx = { .version = 0, .info = pThis, .retain = NULL, .release = NULL, .copyDescription = NULL };
     2865    pThis->hThreadPort = CFMachPortCreate(NULL /*allocator*/, drvHostAudioCaThreadPortCallback, &PortCtx, NULL);
     2866    AssertLogRelReturn(pThis->hThreadPort != NULL, VERR_NO_MEMORY);
     2867
     2868    pThis->hThreadPortSrc = CFMachPortCreateRunLoopSource(NULL, pThis->hThreadPort, 0 /*order*/);
     2869    AssertLogRelReturn(pThis->hThreadPortSrc != NULL, VERR_NO_MEMORY);
     2870
     2871    rc = RTThreadCreateF(&pThis->hThread, drvHostAudioCaThread, pThis, 0, RTTHREADTYPE_IO,
     2872                         RTTHREADFLAGS_WAITABLE, "CaAud-%u", pDrvIns->iInstance);
     2873    AssertLogRelMsgReturn(RT_SUCCESS(rc), ("RTThreadCreateF failed: %Rrc\n", rc), rc);
     2874
     2875    RTThreadUserWait(pThis->hThread, RT_MS_10SEC);
     2876    AssertLogRel(pThis->hThreadRunLoop);
     2877#endif
     2878
     2879#ifdef CORE_AUDIO_WITH_BREAKPOINT_TIMER
     2880    /*
     2881     * Create a IPRT timer.  The TM timers won't necessarily work as EMT is probably busy.
     2882     */
     2883    rc = RTTimerLRCreateEx(&pThis->hBreakpointTimer, 0 /*no interval*/, 0, drvHostAudioCaBreakpointTimer, pThis);
     2884    AssertRCReturn(rc, rc);
     2885#endif
    26852886
    26862887    /*
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