Changeset 89165 in vbox
- Timestamp:
- May 19, 2021 1:21:08 PM (4 years ago)
- svn:sync-xref-src-repo-rev:
- 144506
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Audio/DrvHostAudioCoreAudio.cpp
r89133 r89165 47 47 48 48 #include <iprt/uuid.h> 49 #include <iprt/timer.h> 49 50 50 51 #include <CoreAudio/CoreAudio.h> … … 53 54 #include <AudioToolbox/AudioConverter.h> 54 55 #include <AudioToolbox/AudioToolbox.h> 55 56 57 58 /* Enables utilizing the Core Audio converter unit for converting59 * input / output from/to our requested formats. That might be more60 * 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_CONVERTER63 64 /** @todo65 * - Maybe make sure the threads are immediately stopped if playing/recording stops.66 */67 56 68 57 … … 74 63 /** The minimum number of queue buffers. */ 75 64 #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 76 80 77 81 … … 284 288 /** Indicates whether we've registered default output device change listener. */ 285 289 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 286 308 /** Critical section to serialize access. */ 287 309 RTCRITSECT CritSect; 310 #ifdef CORE_AUDIO_WITH_BREAKPOINT_TIMER 311 /** Timder for debugging AudioQueueDispose slowness. */ 312 RTTIMERLR hBreakpointTimer; 313 #endif 288 314 } DRVHOSTCOREAUDIO; 289 315 … … 803 829 804 830 /********************************************************************************************************************************* 831 * Worker Thread * 832 *********************************************************************************************************************************/ 833 #ifdef CORE_AUDIO_WITH_WORKER_THREAD 834 835 /** 836 * Message handling callback for CFMachPort. 837 */ 838 static 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 */ 848 static 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 /********************************************************************************************************************************* 805 890 * PDMIHOSTAUDIO * 806 891 *********************************************************************************************************************************/ … … 1615 1700 * related thread if we don't specify a runloop here. That's simpler. 1616 1701 */ 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 1617 1709 OSStatus orc; 1618 1710 if (pCfgReq->enmDir == PDMAUDIODIR_OUT) 1619 1711 orc = AudioQueueNewOutput(&pStreamCA->BasicStreamDesc, drvHostAudioCaOutputQueueBufferCallback, pStreamCA, 1620 NULL /*hRunLoop*/, NULL /*pStrRlMode*/, 0 /*fFlags - MBZ*/, &pStreamCA->hAudioQueue);1712 hRunLoop, hRunLoopMode, 0 /*fFlags - MBZ*/, &pStreamCA->hAudioQueue); 1621 1713 else 1622 1714 orc = AudioQueueNewInput(&pStreamCA->BasicStreamDesc, drvHostAudioCaInputQueueBufferCallback, pStreamCA, 1623 NULL /*hRunLoop*/, NULL /*pStrRlMode*/, 0 /*fFlags - MBZ*/, &pStreamCA->hAudioQueue);1715 hRunLoop, hRunLoopMode, 0 /*fFlags - MBZ*/, &pStreamCA->hAudioQueue); 1624 1716 if (orc == noErr) 1625 1717 { … … 1746 1838 1747 1839 /** 1840 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamInitAsync} 1841 */ 1842 static 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 /** 1748 1850 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamDestroy} 1749 1851 */ … … 1783 1885 * Free the queue buffers and the queue. 1784 1886 */ 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 1785 1894 if (pStreamCA->paBuffers) 1786 1895 { … … 1806 1915 } 1807 1916 1917 #ifdef CORE_AUDIO_WITH_BREAKPOINT_TIMER 1918 RTTimerLRStop(pThis->hBreakpointTimer); 1919 LogRel(("Queue-destruction: %'RU64\n", RTTimeNanoTS() - nsStart)); 1920 #endif 1921 1808 1922 /* 1809 1923 * Release the device and delete the critsect. … … 1824 1938 return VINF_SUCCESS; 1825 1939 } 1940 1941 1942 #ifdef CORE_AUDIO_WITH_BREAKPOINT_TIMER 1943 /** @callback_method_impl{FNRTTIMERLR, For debugging things that takes too long.} */ 1944 static 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 1826 1952 1827 1953 … … 2638 2764 drvHostAudioCaRemoveDefaultDeviceListners(pThis); 2639 2765 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 2640 2808 int rc2 = RTCritSectDelete(&pThis->CritSect); 2641 2809 AssertRC(rc2); … … 2660 2828 */ 2661 2829 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 2662 2836 PDMAudioHostEnumInit(&pThis->Devices); 2663 2837 /* IBase */ … … 2670 2844 pThis->IHostAudio.pfnStreamConfigHint = NULL; 2671 2845 pThis->IHostAudio.pfnStreamCreate = drvHostAudioCaHA_StreamCreate; 2672 pThis->IHostAudio.pfnStreamInitAsync = NULL;2846 pThis->IHostAudio.pfnStreamInitAsync = drvHostAudioCaHA_StreamInitAsync; 2673 2847 pThis->IHostAudio.pfnStreamDestroy = drvHostAudioCaHA_StreamDestroy; 2674 2848 pThis->IHostAudio.pfnStreamNotifyDeviceChanged = NULL; … … 2683 2857 int rc = RTCritSectInit(&pThis->CritSect); 2684 2858 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 2685 2886 2686 2887 /*
Note:
See TracChangeset
for help on using the changeset viewer.