VirtualBox

Changeset 63711 in vbox for trunk/src/VBox


Ignore:
Timestamp:
Sep 5, 2016 12:04:01 PM (8 years ago)
Author:
vboxsync
Message:

Audio: Implemented support for audio device enumeration handling, audio device information and audio backend notifications. This will enable to let the backends tell the audio subsystem that the host audio configuration has changed and react accordingly to it. For now only the Core Audio backend supports device enumeration. Further this also will get rid of the static initialization on the device emulation side, which, if at VM startup no audio input(s) / output(s) were available, was triggering a warning. The NULL backend therefore does not need to act as a (static) fallback anymore.

Work in progress.

Location:
trunk/src/VBox
Files:
15 edited

Legend:

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

    r63690 r63711  
    375375    /** Number of active (running) SDn streams. */
    376376    uint8_t                 cStreamsActive;
    377 #ifndef VBOX_WITH_AUDIO_CALLBACKS
     377#ifndef VBOX_WITH_AUDIO_AC97_CALLBACKS
    378378    /** The timer for pumping data thru the attached LUN drivers. */
    379379    PTMTIMERR3              pTimer;
     
    424424#ifndef VBOX_DEVICE_STRUCT_TESTCASE
    425425
     426#if 0 /* unused */
    426427static void ichac97DestroyIn(PAC97STATE pThis, PDMAUDIORECSOURCE enmRecSource);
    427428static void ichac97DestroyOut(PAC97STATE pThis);
     429#endif
    428430DECLINLINE(PAC97STREAM) ichac97GetStreamFromID(PAC97STATE pThis, uint32_t uID);
    429431static int ichac97StreamInit(PAC97STATE pThis, PAC97STREAM pStream, uint8_t u8Strm);
    430432static DECLCALLBACK(void) ichac97Reset(PPDMDEVINS pDevIns);
    431 #ifndef VBOX_WITH_AUDIO_CALLBACKS
     433#ifndef VBOX_WITH_AUDIO_AC97_CALLBACKS
    432434static void ichac97TimerMaybeStart(PAC97STATE pThis);
    433435static void ichac97TimerMaybeStop(PAC97STATE pThis);
     
    560562            pThis->cStreamsActive--;
    561563
    562 #ifndef VBOX_WITH_AUDIO_CALLBACKS
     564#ifndef VBOX_WITH_AUDIO_AC97_CALLBACKS
    563565        ichac97TimerMaybeStop(pThis);
    564566#endif
     
    567569    {
    568570        pThis->cStreamsActive++;
    569 #ifndef VBOX_WITH_AUDIO_CALLBACKS
     571#ifndef VBOX_WITH_AUDIO_AC97_CALLBACKS
    570572        ichac97TimerMaybeStart(pThis);
    571573#endif
     
    621623}
    622624
     625#if 0 /* unused */
    623626static void ichac97StreamsDestroy(PAC97STATE pThis)
    624627{
     
    633636    ichac97StreamDestroy(&pThis->StreamOut);
    634637}
     638#endif
    635639
    636640static int ichac97StreamsInit(PAC97STATE pThis)
     
    672676}
    673677
     678#if 0 /* unused */
    674679static void ichac97DestroyIn(PAC97STATE pThis, PDMAUDIORECSOURCE enmRecSource)
    675680{
     
    728733    }
    729734}
     735#endif
    730736
    731737static int ichac97CreateIn(PAC97STATE pThis,
     
    13441350}
    13451351
    1346 #ifndef VBOX_WITH_AUDIO_CALLBACKS
    1347 
     1352#ifndef VBOX_WITH_AUDIO_AC97_CALLBACKS
    13481353static void ichac97TimerMaybeStart(PAC97STATE pThis)
    13491354{
     
    14491454    STAM_PROFILE_STOP(&pThis->StatTimer, a);
    14501455}
    1451 
    1452 #endif /* !VBOX_WITH_AUDIO_CALLBACKS */
     1456#endif /* !VBOX_WITH_AUDIO_AC97_CALLBACKS */
    14531457
    14541458static int ichac97TransferAudio(PAC97STATE pThis, PAC97STREAM pStream, uint32_t cbToProcess, uint32_t *pcbProcessed)
     
    25812585                                N_("AC'97 configuration error: Querying \"Codec\" as string failed"));
    25822586
    2583 #ifndef VBOX_WITH_AUDIO_CALLBACKS
     2587#ifndef VBOX_WITH_AUDIO_AC97_CALLBACKS
    25842588    uint16_t uTimerHz;
    25852589    rc = CFGMR3QueryU16Def(pCfg, "TimerHz", &uTimerHz, AC97_TIMER_HZ /* Default value, if not set. */);
     
    27142718
    27152719    if (RT_SUCCESS(rc))
    2716     {
    27172720        ichac97StreamsInit(pThis);
    27182721
    2719         PAC97DRIVER pDrv;
    2720         RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
    2721         {
    2722             /*
    2723              * Only primary drivers are critical for the VM to run. Everything else
    2724              * might not worth showing an own error message box in the GUI.
    2725              */
    2726             if (!(pDrv->Flags & PDMAUDIODRVFLAGS_PRIMARY))
    2727                 continue;
    2728 
    2729             PPDMIAUDIOCONNECTOR pCon = pDrv->pConnector;
    2730             AssertPtr(pCon);
    2731 
    2732             bool fValidLineIn = AudioMixerStreamIsValid(pDrv->LineIn.pMixStrm);
    2733             bool fValidMicIn  = AudioMixerStreamIsValid(pDrv->MicIn.pMixStrm);
    2734             bool fValidOut    = AudioMixerStreamIsValid(pDrv->Out.pMixStrm);
    2735 
    2736             if (    !fValidLineIn
    2737                  && !fValidMicIn
    2738                  && !fValidOut)
    2739             {
    2740                 LogRel(("AC97: Falling back to NULL backend (no sound audible)\n"));
    2741 
    2742                 /* Destroy the streams before re-attaching the NULL driver. */
    2743                 ichac97StreamsDestroy(pThis);
    2744 
    2745                 ichac97Reset(pDevIns);
    2746                 ichac97Reattach(pThis, pDrv, pDrv->uLUN, "NullAudio");
    2747 
    2748                 ichac97StreamsInit(pThis);
    2749 
    2750                 PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "HostAudioNotResponding",
    2751                     N_("No audio devices could be opened. Selecting the NULL audio backend "
    2752                        "with the consequence that no sound is audible"));
    2753             }
    2754             else
    2755             {
    2756                 bool fWarn = false;
    2757 
    2758                 PDMAUDIOBACKENDCFG backendCfg;
    2759                 int rc2 = pCon->pfnGetConfig(pCon, &backendCfg);
    2760                 if (RT_SUCCESS(rc2))
    2761                 {
    2762                     if (backendCfg.cSources)
    2763                     {
    2764                         /* If the audio backend supports two or more input streams at once,
    2765                          * warn if one of our two inputs (microphone-in and line-in) failed to initialize. */
    2766                         if (backendCfg.cMaxStreamsIn >= 2)
    2767                             fWarn = !fValidLineIn || !fValidMicIn;
    2768                         /* If the audio backend only supports one input stream at once (e.g. pure ALSA, and
    2769                          * *not* ALSA via PulseAudio plugin!), only warn if both of our inputs failed to initialize.
    2770                          * One of the two simply is not in use then. */
    2771                         else if (backendCfg.cMaxStreamsIn == 1)
    2772                             fWarn = !fValidLineIn && !fValidMicIn;
    2773                         /* Don't warn if our backend is not able of supporting any input streams at all. */
    2774                     }
    2775 
    2776                     if (   !fWarn
    2777                         && backendCfg.cSinks)
    2778                     {
    2779                         fWarn = !fValidOut;
    2780                     }
    2781                 }
    2782                 else
    2783                 {
    2784                     LogRel(("AC97: Unable to retrieve audio backend configuration for LUN #%RU8, rc=%Rrc\n", pDrv->uLUN, rc2));
    2785                     fWarn = true;
    2786                 }
    2787 
    2788                 if (fWarn)
    2789                 {
    2790                     char   szMissingStreams[255] = "";
    2791                     size_t len = 0;
    2792                     if (!fValidLineIn)
    2793                     {
    2794                         LogRel(("AC97: WARNING: Unable to open PCM line input for LUN #%RU8!\n", pDrv->uLUN));
    2795                         len = RTStrPrintf(szMissingStreams, sizeof(szMissingStreams), "PCM Input");
    2796                     }
    2797                     if (!fValidMicIn)
    2798                     {
    2799                         LogRel(("AC97: WARNING: Unable to open PCM microphone input for LUN #%RU8!\n", pDrv->uLUN));
    2800                         len += RTStrPrintf(szMissingStreams + len,
    2801                                            sizeof(szMissingStreams) - len, len ? ", PCM Microphone" : "PCM Microphone");
    2802                     }
    2803                     if (!fValidOut)
    2804                     {
    2805                         LogRel(("AC97: WARNING: Unable to open PCM output for LUN #%RU8!\n", pDrv->uLUN));
    2806                         len += RTStrPrintf(szMissingStreams + len,
    2807                                            sizeof(szMissingStreams) - len, len ? ", PCM Output" : "PCM Output");
    2808                     }
    2809 
    2810                     PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "HostAudioNotResponding",
    2811                                                N_("Some AC'97 audio streams (%s) could not be opened. Guest applications generating audio "
    2812                                                   "output or depending on audio input may hang. Make sure your host audio device "
    2813                                                   "is working properly. Check the logfile for error messages of the audio "
    2814                                                   "subsystem"), szMissingStreams);
    2815                 }
    2816             }
    2817         }
    2818     }
    2819 
    2820 # ifndef VBOX_WITH_AUDIO_CALLBACKS
     2722# ifndef VBOX_WITH_AUDIO_AC97_CALLBACKS
    28212723    if (RT_SUCCESS(rc))
    28222724    {
     
    28352737        }
    28362738    }
    2837 # else
     2739# else /* !VBOX_WITH_AUDIO_AC97_CALLBACKS */
    28382740    if (RT_SUCCESS(rc))
    28392741    {
     
    28652767        }
    28662768    }
    2867 # endif
     2769# endif /* VBOX_WITH_AUDIO_AC97_CALLBACKS */
    28682770
    28692771# ifdef VBOX_WITH_STATISTICS
  • trunk/src/VBox/Devices/Audio/DevIchHda.cpp

    r63690 r63711  
    820820    /** Number of active (running) SDn streams. */
    821821    uint8_t                            cStreamsActive;
    822 #ifndef VBOX_WITH_AUDIO_CALLBACKS
     822#ifndef VBOX_WITH_AUDIO_HDA_CALLBACKS
    823823    /** The timer for pumping data thru the attached LUN drivers. */
    824824    PTMTIMERR3                         pTimer;
     
    833833#endif
    834834#ifdef VBOX_WITH_STATISTICS
    835 # ifndef VBOX_WITH_AUDIO_CALLBACKS
     835# ifndef VBOX_WITH_AUDIO_HDA_CALLBACKS
    836836    STAMPROFILE                        StatTimer;
    837837# endif
     
    868868typedef HDASTATE *PHDASTATE;
    869869
    870 #ifdef VBOX_WITH_AUDIO_CALLBACKS
     870#ifdef VBOX_WITH_AUDIO_HDA_CALLBACKS
    871871typedef struct HDACALLBACKCTX
    872872{
     
    976976 * Timer routines.
    977977 */
    978 #if !defined(VBOX_WITH_AUDIO_CALLBACKS) && defined(IN_RING3)
     978#if !defined(VBOX_WITH_AUDIO_HDA_CALLBACKS) && defined(IN_RING3)
    979979static void hdaTimerMaybeStart(PHDASTATE pThis);
    980980static void hdaTimerMaybeStop(PHDASTATE pThis);
     
    18281828            pThis->cStreamsActive--;
    18291829
    1830 # ifndef VBOX_WITH_AUDIO_CALLBACKS
     1830# ifndef VBOX_WITH_AUDIO_HDA_CALLBACKS
    18311831        hdaTimerMaybeStop(pThis);
    18321832# endif
     
    18351835    {
    18361836        pThis->cStreamsActive++;
    1837 # ifndef VBOX_WITH_AUDIO_CALLBACKS
     1837# ifndef VBOX_WITH_AUDIO_HDA_CALLBACKS
    18381838        hdaTimerMaybeStart(pThis);
    18391839# endif
     
    41334133}
    41344134
    4135 #ifndef VBOX_WITH_AUDIO_CALLBACKS
    4136 
     4135#ifndef VBOX_WITH_AUDIO_HDA_CALLBACKS
    41374136static void hdaTimerMaybeStart(PHDASTATE pThis)
    41384137{
     
    42704269}
    42714270
    4272 #else /* VBOX_WITH_AUDIO_CALLBACKS */
    4273 
    4274 static DECLCALLBACK(int) hdaCallbackInput(PDMAUDIOCALLBACKTYPE enmType, void *pvCtx, size_t cbCtx, void *pvUser, size_t cbUser)
     4271#else /* VBOX_WITH_AUDIO_HDA_CALLBACKS */
     4272
     4273static DECLCALLBACK(int) hdaCallbackInput(PDMAUDIOCBTYPE enmType, void *pvCtx, size_t cbCtx, void *pvUser, size_t cbUser)
    42754274{
    42764275    Assert(enmType == PDMAUDIOCALLBACKTYPE_INPUT);
     
    42834282    AssertReturn(cbCtx == sizeof(HDACALLBACKCTX), VERR_INVALID_PARAMETER);
    42844283
    4285     PPDMAUDIOCALLBACKDATAIN pData = (PPDMAUDIOCALLBACKDATAIN)pvUser;
    4286     AssertReturn(cbUser == sizeof(PDMAUDIOCALLBACKDATAIN), VERR_INVALID_PARAMETER);
     4284    PPDMAUDIOCBDATA_DATA_INPUT pData = (PPDMAUDIOCBDATA_DATA_INPUT)pvUser;
     4285    AssertReturn(cbUser == sizeof(PDMAUDIOCBDATA_DATA_INPUT), VERR_INVALID_PARAMETER);
    42874286
    42884287    return hdaTransfer(pCtx->pThis, PI_INDEX, UINT32_MAX, &pData->cbOutRead);
    42894288}
    42904289
    4291 static DECLCALLBACK(int) hdaCallbackOutput(PDMAUDIOCALLBACKTYPE enmType, void *pvCtx, size_t cbCtx, void *pvUser, size_t cbUser)
     4290static DECLCALLBACK(int) hdaCallbackOutput(PDMAUDIOCBTYPE enmType, void *pvCtx, size_t cbCtx, void *pvUser, size_t cbUser)
    42924291{
    42934292    Assert(enmType == PDMAUDIOCALLBACKTYPE_OUTPUT);
     
    43004299    AssertReturn(cbCtx == sizeof(HDACALLBACKCTX), VERR_INVALID_PARAMETER);
    43014300
    4302     PPDMAUDIOCALLBACKDATAOUT pData = (PPDMAUDIOCALLBACKDATAOUT)pvUser;
    4303     AssertReturn(cbUser == sizeof(PDMAUDIOCALLBACKDATAOUT), VERR_INVALID_PARAMETER);
     4301    PPDMAUDIOCBDATA_DATA_OUTPUT pData = (PPDMAUDIOCBDATA_DATA_OUTPUT)pvUser;
     4302    AssertReturn(cbUser == sizeof(PDMAUDIOCBDATA_DATA_OUTPUT), VERR_INVALID_PARAMETER);
    43044303
    43054304    PHDASTATE pThis = pCtx->pThis;
     
    43184317    }
    43194318}
    4320 #endif /* VBOX_WITH_AUDIO_CALLBACKS */
     4319#endif /* VBOX_WITH_AUDIO_HDA_CALLBACKS */
    43214320
    43224321static int hdaTransfer(PHDASTATE pThis, PHDASTREAM pStream, uint32_t cbToProcess, uint32_t *pcbProcessed)
     
    54895488    LogFlowFuncEnter();
    54905489
    5491 # ifndef VBOX_WITH_AUDIO_CALLBACKS
     5490# ifndef VBOX_WITH_AUDIO_HDA_CALLBACKS
    54925491    /*
    54935492     * Stop the timer, if any.
     
    55725571    HDA_REG(pThis, STATESTS) = 0x1;
    55735572
    5574 # ifndef VBOX_WITH_AUDIO_CALLBACKS
     5573# ifndef VBOX_WITH_AUDIO_HDA_CALLBACKS
    55755574    hdaTimerMaybeStart(pThis);
    55765575# endif
     
    58305829        return PDMDEV_SET_ERROR(pDevIns, rc,
    58315830                                N_("HDA configuration error: failed to read R0Enabled as boolean"));
    5832 #ifndef VBOX_WITH_AUDIO_CALLBACKS
     5831#ifndef VBOX_WITH_AUDIO_HDA_CALLBACKS
    58335832    uint16_t uTimerHz;
    58345833    rc = CFGMR3QueryU16Def(pCfg, "TimerHz", &uTimerHz, 200 /* Hz */);
     
    60596058            AssertRC(rc);
    60606059        }
    6061 
    6062         /*
    6063          * Initialize the driver chain.
    6064          */
    6065         PHDADRIVER pDrv;
    6066         RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
    6067         {
    6068             /*
    6069              * Only primary drivers are critical for the VM to run. Everything else
    6070              * might not worth showing an own error message box in the GUI.
    6071              */
    6072             if (!(pDrv->Flags & PDMAUDIODRVFLAGS_PRIMARY))
    6073                 continue;
    6074 
    6075             PPDMIAUDIOCONNECTOR pCon = pDrv->pConnector;
    6076             AssertPtr(pCon);
    6077 
    6078             bool fValidLineIn = AudioMixerStreamIsValid(pDrv->LineIn.pMixStrm);
    6079 #ifdef VBOX_WITH_HDA_MIC_IN
    6080             bool fValidMicIn  = AudioMixerStreamIsValid(pDrv->MicIn.pMixStrm);
    6081 #endif
    6082             bool fValidOut    = AudioMixerStreamIsValid(pDrv->Front.pMixStrm);
    6083 #ifdef VBOX_WITH_HDA_51_SURROUND
    6084             /** @todo Anything to do here? */
    6085 #endif
    6086 
    6087             if (    !fValidLineIn
    6088 #ifdef VBOX_WITH_HDA_MIC_IN
    6089                  && !fValidMicIn
    6090 #endif
    6091                  && !fValidOut)
    6092             {
    6093                 LogRel(("HDA: Falling back to NULL backend (no sound audible)\n"));
    6094 
    6095                 hdaReset(pDevIns);
    6096                 hdaReattach(pThis, pDrv, pDrv->uLUN, "NullAudio");
    6097 
    6098                 PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "HostAudioNotResponding",
    6099                     N_("No audio devices could be opened. Selecting the NULL audio backend "
    6100                        "with the consequence that no sound is audible"));
    6101             }
    6102             else
    6103             {
    6104                 bool fWarn = false;
    6105 
    6106                 PDMAUDIOBACKENDCFG backendCfg;
    6107                 int rc2 = pCon->pfnGetConfig(pCon, &backendCfg);
    6108                 if (RT_SUCCESS(rc2))
    6109                 {
    6110                     if (backendCfg.cSources)
    6111                     {
    6112 #ifdef VBOX_WITH_HDA_MIC_IN
    6113                         /* If the audio backend supports two or more input streams at once,
    6114                          * warn if one of our two inputs (microphone-in and line-in) failed to initialize. */
    6115                         if (backendCfg.cMaxStreamsIn >= 2)
    6116                             fWarn = !fValidLineIn || !fValidMicIn;
    6117                         /* If the audio backend only supports one input stream at once (e.g. pure ALSA, and
    6118                          * *not* ALSA via PulseAudio plugin!), only warn if both of our inputs failed to initialize.
    6119                          * One of the two simply is not in use then. */
    6120                         else if (backendCfg.cMaxStreamsIn == 1)
    6121                             fWarn = !fValidLineIn && !fValidMicIn;
    6122                         /* Don't warn if our backend is not able of supporting any input streams at all. */
    6123 #else
    6124                         /* We only have line-in as input source. */
    6125                         fWarn = !fValidLineIn;
    6126 #endif
    6127                     }
    6128 
    6129                     if (   !fWarn
    6130                         && backendCfg.cSinks)
    6131                     {
    6132                         fWarn = !fValidOut;
    6133                     }
    6134                 }
    6135                 else
    6136                 {
    6137                     LogRel(("HDA: Unable to retrieve audio backend configuration for LUN #%RU8, rc=%Rrc\n", pDrv->uLUN, rc2));
    6138                     fWarn = true;
    6139                 }
    6140 
    6141                 if (fWarn)
    6142                 {
    6143                     char   szMissingStreams[255];
    6144                     size_t len = 0;
    6145                     if (!fValidLineIn)
    6146                     {
    6147                         LogRel(("HDA: WARNING: Unable to open PCM line input for LUN #%RU8!\n", pDrv->uLUN));
    6148                         len = RTStrPrintf(szMissingStreams, sizeof(szMissingStreams), "PCM Input");
    6149                     }
    6150 #ifdef VBOX_WITH_HDA_MIC_IN
    6151                     if (!fValidMicIn)
    6152                     {
    6153                         LogRel(("HDA: WARNING: Unable to open PCM microphone input for LUN #%RU8!\n", pDrv->uLUN));
    6154                         len += RTStrPrintf(szMissingStreams + len,
    6155                                            sizeof(szMissingStreams) - len, len ? ", PCM Microphone" : "PCM Microphone");
    6156                     }
    6157 #endif
    6158                     if (!fValidOut)
    6159                     {
    6160                         LogRel(("HDA: WARNING: Unable to open PCM output for LUN #%RU8!\n", pDrv->uLUN));
    6161                         len += RTStrPrintf(szMissingStreams + len,
    6162                                            sizeof(szMissingStreams) - len, len ? ", PCM Output" : "PCM Output");
    6163                     }
    6164 
    6165                     PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "HostAudioNotResponding",
    6166                                                N_("Some HDA audio streams (%s) could not be opened. Guest applications generating audio "
    6167                                                   "output or depending on audio input may hang. Make sure your host audio device "
    6168                                                   "is working properly. Check the logfile for error messages of the audio "
    6169                                                   "subsystem"), szMissingStreams);
    6170                 }
    6171             }
    6172         }
    61736060    }
    61746061
     
    62546141    }
    62556142
    6256 # ifndef VBOX_WITH_AUDIO_CALLBACKS
     6143# ifndef VBOX_WITH_AUDIO_HDA_CALLBACKS
    62576144    if (RT_SUCCESS(rc))
    62586145    {
     
    63096196         * Register statistics.
    63106197         */
    6311 #  ifndef VBOX_WITH_AUDIO_CALLBACKS
     6198#  ifndef VBOX_WITH_AUDIO_HDA_CALLBACKS
    63126199        PDMDevHlpSTAMRegister(pDevIns, &pThis->StatTimer,            STAMTYPE_PROFILE, "/Devices/HDA/Timer",             STAMUNIT_TICKS_PER_CALL, "Profiling hdaTimer.");
    63136200#  endif
  • trunk/src/VBox/Devices/Audio/DevSB16.cpp

    r63478 r63711  
    182182    /** Number of active (running) SDn streams. */
    183183    uint8_t                        cStreamsActive;
    184 #ifndef VBOX_WITH_AUDIO_CALLBACKS
     184#ifndef VBOX_WITH_AUDIO_SB16_CALLBACKS
    185185    /** The timer for pumping data thru the attached LUN drivers. */
    186186    PTMTIMERR3                     pTimerIO;
     
    205205static int sb16OpenOut(PSB16STATE pThis, PPDMAUDIOSTREAMCFG pCfg);
    206206static void sb16CloseOut(PSB16STATE pThis);
    207 #ifndef VBOX_WITH_AUDIO_CALLBACKS
     207#ifndef VBOX_WITH_AUDIO_SB16_CALLBACKS
    208208static void sb16TimerMaybeStart(PSB16STATE pThis);
    209209static void sb16TimerMaybeStop(PSB16STATE pThis);
     
    448448    if (hold)
    449449    {
    450 #ifndef VBOX_WITH_AUDIO_CALLBACKS
     450#ifndef VBOX_WITH_AUDIO_SB16_CALLBACKS
    451451        pThis->cStreamsActive++;
    452452        sb16TimerMaybeStart(pThis);
     
    454454        PDMDevHlpDMASchedule(pThis->pDevInsR3);
    455455    }
    456 #ifndef VBOX_WITH_AUDIO_CALLBACKS
     456#ifndef VBOX_WITH_AUDIO_SB16_CALLBACKS
    457457    else
    458458    {
     
    17561756}
    17571757
    1758 #ifndef VBOX_WITH_AUDIO_CALLBACKS
    1759 
     1758#ifndef VBOX_WITH_AUDIO_SB16_CALLBACKS
    17601759static void sb16TimerMaybeStart(PSB16STATE pThis)
    17611760{
     
    18911890    }
    18921891}
    1893 
    1894 #endif /* !VBOX_WITH_AUDIO_CALLBACKS */
     1892#endif /* !VBOX_WITH_AUDIO_SB16_CALLBACKS */
    18951893
    18961894static void sb16Save(PSSMHANDLE pSSM, PSB16STATE pThis)
     
    23342332                                N_("SB16 configuration error: Failed to get the \"Version\" value"));
    23352333
    2336 #ifndef VBOX_WITH_AUDIO_CALLBACKS
     2334#ifndef VBOX_WITH_AUDIO_SB16_CALLBACKS
    23372335    uint16_t uTimerHz;
    23382336    rc = CFGMR3QueryU16Def(pCfg, "TimerHz", &uTimerHz, 25 /* Hz */);
     
    24502448    }
    24512449
    2452 #ifndef VBOX_WITH_AUDIO_CALLBACKS
     2450#ifndef VBOX_WITH_AUDIO_SB16_CALLBACKS
    24532451    if (RT_SUCCESS(rc))
    24542452    {
     
    24662464            AssertMsgFailedReturn(("Error creating I/O timer, rc=%Rrc\n", rc), rc);
    24672465    }
    2468 #else
     2466#else /* !VBOX_WITH_AUDIO_SB16_CALLBACKS */
    24692467    if (RT_SUCCESS(rc))
    24702468    {
     
    24982496        }
    24992497    }
    2500 #endif
     2498#endif /* VBOX_WITH_AUDIO_SB16_CALLBACKS */
    25012499
    25022500    return VINF_SUCCESS;
  • trunk/src/VBox/Devices/Audio/DrvAudio.cpp

    r63684 r63711  
    4444static int drvAudioStreamControlInternalBackend(PDRVAUDIO pThis, PPDMAUDIOSTREAM pStream, PDMAUDIOSTREAMCMD enmStreamCmd);
    4545static int drvAudioStreamControlInternal(PDRVAUDIO pThis, PPDMAUDIOSTREAM pStream, PDMAUDIOSTREAMCMD enmStreamCmd);
    46 static int drvAudioStreamDestroyInBackendInternal(PDRVAUDIO pThis, PPDMAUDIOSTREAM pHstStream);
     46static int drvAudioStreamCreateInternalBackend(PDRVAUDIO pThis, PPDMAUDIOSTREAM pHstStream, PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq);
     47static int drvAudioStreamDestroyInternalBackend(PDRVAUDIO pThis, PPDMAUDIOSTREAM pHstStream);
    4748static int drvAudioStreamUninitInternal(PDRVAUDIO pThis, PPDMAUDIOSTREAM pStream);
    4849static int drvAudioStreamInitInternal(PDRVAUDIO pThis, PPDMAUDIOSTREAM pStream, PPDMAUDIOSTREAMCFG pCfgHost, PPDMAUDIOSTREAMCFG pCfgGuest);
    4950static int drvAudioStreamIterateInternal(PDRVAUDIO pThis, PPDMAUDIOSTREAM pStream);
    5051static int drvAudioStreamReInitInternal(PDRVAUDIO pThis, PPDMAUDIOSTREAM pStream);
     52static int drvAudioStreamLinkToInternal(PPDMAUDIOSTREAM pStream, PPDMAUDIOSTREAM pPair);
    5153
    5254#ifndef VBOX_AUDIO_TESTCASE
     
    525527     */
    526528
    527     /* Make the acquired host configuration the requested host configuration initially,
    528      * in case the backend does not report back an acquired configuration. */
    529     PDMAUDIOSTREAMCFG CfgHostAcq;
    530     memcpy(&CfgHostAcq, pCfgHost, sizeof(PDMAUDIOSTREAMCFG));
    531 
    532529#ifdef DEBUG
    533530    LogFunc(("[%s] Requested host format:\n", pStream->szName));
     
    541538#endif
    542539
    543     int rc = pThis->pHostDrvAudio->pfnStreamCreate(pThis->pHostDrvAudio, pHstStream,
    544                                                    pCfgHost /* pCfgReq */, &CfgHostAcq /* pCfgAcq */);
     540    PDMAUDIOSTREAMCFG CfgHostAcq;
     541    int rc = drvAudioStreamCreateInternalBackend(pThis,pHstStream, pCfgHost, &CfgHostAcq);
    545542    if (RT_FAILURE(rc))
    546     {
    547         LogRel2(("Audio: Creating stream '%s' in backend failed with %Rrc\n", pStream->szName, rc));
    548543        return rc;
    549     }
    550 
    551     /* Only set the host's stream to initialized if we were able create the stream
    552      * in the host backend. This is necessary for trying to re-initialize the stream
    553      * at some later point in time. */
    554     pHstStream->fStatus |= PDMAUDIOSTRMSTS_FLAG_INITIALIZED;
    555544
    556545#ifdef DEBUG
     
    599588    AssertRC(rc2);
    600589
    601 #ifdef VBOX_WITH_STATISTICS
    602     char szStatName[255];
    603 #endif
    604 
    605590    if (pCfgGuest->enmDir == PDMAUDIODIR_IN)
    606591    {
     
    608593        rc2 = AudioMixBufLinkTo(&pHstStream->MixBuf, &pGstStream->MixBuf);
    609594        AssertRC(rc2);
    610 
    611 #ifdef VBOX_WITH_STATISTICS
    612         RTStrPrintf(szStatName, sizeof(szStatName), "Guest/%s/BytesElapsed", pGstStream->szName);
    613         PDMDrvHlpSTAMRegCounterEx(pThis->pDrvIns, &pGstStream->In.StatBytesElapsed,
    614                                   szStatName, STAMUNIT_BYTES, "Elapsed bytes read.");
    615 
    616         RTStrPrintf(szStatName, sizeof(szStatName), "Guest/%s/BytesRead", pGstStream->szName);
    617         PDMDrvHlpSTAMRegCounterEx(pThis->pDrvIns, &pGstStream->In.StatBytesTotalRead,
    618                                   szStatName, STAMUNIT_BYTES, "Total bytes read.");
    619 
    620         RTStrPrintf(szStatName, sizeof(szStatName), "Host/%s/SamplesCaptured", pHstStream->szName);
    621         PDMDrvHlpSTAMRegCounterEx(pThis->pDrvIns, &pHstStream->In.StatSamplesCaptured,
    622                                   szStatName, STAMUNIT_COUNT, "Total samples captured.");
    623 #endif
    624595    }
    625596    else
     
    628599        rc2 = AudioMixBufLinkTo(&pGstStream->MixBuf, &pHstStream->MixBuf);
    629600        AssertRC(rc2);
    630 
    631 #ifdef VBOX_WITH_STATISTICS
    632         RTStrPrintf(szStatName, sizeof(szStatName), "Guest/%s/BytesElapsed", pGstStream->szName);
    633         PDMDrvHlpSTAMRegCounterEx(pThis->pDrvIns, &pGstStream->Out.StatBytesElapsed,
    634                                   szStatName, STAMUNIT_BYTES, "Elapsed bytes written.");
    635 
    636         RTStrPrintf(szStatName, sizeof(szStatName), "Guest/%s/BytesRead", pGstStream->szName);
    637         PDMDrvHlpSTAMRegCounterEx(pThis->pDrvIns, &pGstStream->Out.StatBytesTotalWritten,
    638                                   szStatName, STAMUNIT_BYTES, "Total bytes written.");
    639 
    640         RTStrPrintf(szStatName, sizeof(szStatName), "Host/%s/SamplesPlayed", pHstStream->szName);
    641         PDMDrvHlpSTAMRegCounterEx(pThis->pDrvIns, &pHstStream->Out.StatSamplesPlayed,
    642                                   szStatName, STAMUNIT_COUNT, "Total samples played.");
    643 #endif
    644601    }
    645602
     
    655612
    656613/**
     614 * Schedules a re-initialization of all current audio streams.
     615 * The actual re-initialization will happen at some later point in time.
     616 *
     617 * @returns IPRT status code.
     618 * @param   pThis               Pointer to driver instance.
     619 */
     620static int drvAudioScheduleReInit(PDRVAUDIO pThis)
     621{
     622    AssertPtrReturn(pThis, VERR_INVALID_POINTER);
     623
     624    LogFunc(("\n"));
     625
     626    PPDMAUDIOSTREAM pHstStream;
     627    RTListForEach(&pThis->lstHstStreams, pHstStream, PDMAUDIOSTREAM, Node)
     628        pHstStream->fStatus |= PDMAUDIOSTRMSTS_FLAG_PENDING_REINIT;
     629
     630    return VINF_SUCCESS;
     631}
     632
     633/**
    657634 * Re-initializes an audio stream with its existing host and guest stream configuration.
     635 * This might be the case if the backend told us we need to re-initialize because something
     636 * on the host side has changed.
    658637 *
    659638 * @returns IPRT status code.
     
    672651    AssertPtr(pGstStream);
    673652
    674     int rc;
    675 
    676     if (/* Stream initialized? */
    677             (pHstStream->fStatus & PDMAUDIOSTRMSTS_FLAG_INITIALIZED)
    678         /* Not in pending re-init before? */
    679         && !(pHstStream->fStatus & PDMAUDIOSTRMSTS_FLAG_PENDING_REINIT))
    680     {
    681         /* Disable first. */
    682         rc = pThis->pHostDrvAudio->pfnStreamControl(pThis->pHostDrvAudio, pHstStream, PDMAUDIOSTREAMCMD_DISABLE);
    683         if (RT_FAILURE(rc))
    684         {
    685             LogFunc(("[%s] Error disabling stream, rc=%Rrc\n", pStream->szName, rc));
    686             return rc;
    687         }
    688 
    689         /* Give the backend the chance to clean up the old context. */
    690         rc = pThis->pHostDrvAudio->pfnStreamDestroy(pThis->pHostDrvAudio, pHstStream);
    691         if (RT_FAILURE(rc))
    692         {
    693             LogFunc(("[%s] Error destroying stream in backend, rc=%Rrc\n", pStream->szName, rc));
    694             return rc;
    695         }
    696 
    697         /* Set the pending re-init bit. */
    698         pHstStream->fStatus |= PDMAUDIOSTRMSTS_FLAG_PENDING_REINIT;
    699     }
    700 
    701     LogFlowFunc(("[%s] Host status is 0x%x\n", pStream->szName, pHstStream->fStatus));
    702 
    703     /* Try to re-initialize the stream. */
    704     rc = drvAudioStreamInitInternal(pThis, pStream, &pHstStream->Cfg, &pGstStream->Cfg);
     653    /*
     654     * Gather current stream status.
     655     */
     656    bool fIsEnabled = pHstStream->fStatus & PDMAUDIOSTRMSTS_FLAG_ENABLED; /* Stream is enabled? */
     657
     658    /*
     659     * Destroy and re-create stream on backend side.
     660     */
     661    int rc = drvAudioStreamControlInternalBackend(pThis, pHstStream, PDMAUDIOSTREAMCMD_DISABLE);
    705662    if (RT_SUCCESS(rc))
    706663    {
    707         /* Try to restore the previous stream status, if possible. */
    708         PDMAUDIOSTREAMCMD enmCmdRestore = PDMAUDIOSTREAMCMD_UNKNOWN;
    709 
    710         if (pHstStream->fStatus & PDMAUDIOSTRMSTS_FLAG_ENABLED) /* Stream was running before? */
    711         {
    712             LogFunc(("[%s] Re-enabling host stream ...\n", pStream->szName));
    713             enmCmdRestore = PDMAUDIOSTREAMCMD_ENABLE;
    714         }
    715 
    716         if (enmCmdRestore != PDMAUDIOSTREAMCMD_UNKNOWN)
    717             rc = pThis->pHostDrvAudio->pfnStreamControl(pThis->pHostDrvAudio, pHstStream, PDMAUDIOSTREAMCMD_ENABLE);
    718 
    719         /* Re-initialization successful, remove bit again. */
    720         pHstStream->fStatus &= ~PDMAUDIOSTRMSTS_FLAG_PENDING_REINIT;
    721     }
    722 
    723     LogFunc(("[%s] Reinitialization returned %Rrc\n", pStream->szName, rc));
     664        rc = drvAudioStreamDestroyInternalBackend(pThis, pHstStream);
     665        if (RT_SUCCESS(rc))
     666        {
     667            rc = drvAudioStreamCreateInternalBackend(pThis, pHstStream, &pHstStream->Cfg, NULL /* pCfgAcq */);
     668            /** @todo Validate (re-)acquired configuration with pHstStream->Cfg? */
     669        }
     670    }
     671
     672    /*
     673     * Restore previous stream state.
     674     */
     675    if (RT_SUCCESS(rc))
     676    {
     677        if (fIsEnabled)
     678            rc = drvAudioStreamControlInternalBackend(pThis, pHstStream, PDMAUDIOSTREAMCMD_ENABLE);
     679    }
     680
     681    if (RT_FAILURE(rc))
     682        LogRel2(("Audio: Re-initializing stream '%s' failed with %Rrc\n", pStream->szName, rc));
     683
     684    LogFunc(("[%s] Returning %Rrc\n", pStream->szName, rc));
    724685    return rc;
    725686}
     
    985946
    986947/**
     948 * Links an audio stream to another audio stream (pair).
     949 *
     950 * @returns IPRT status code.
     951 * @param   pStream             Stream to handle linking for.
     952 * @param   pPair               Stream to link pStream to. Specify NULL to unlink pStream from a former linked stream.
     953 */
     954static int drvAudioStreamLinkToInternal(PPDMAUDIOSTREAM pStream, PPDMAUDIOSTREAM pPair)
     955{
     956    if (pPair) /* Link. */
     957    {
     958        pStream->pPair = pPair;
     959        pPair->pPair   = pStream;
     960
     961        LogRel2(("Linked audio stream '%s' to '%s'\n", pStream->szName, pPair->szName));
     962    }
     963    else /* Unlink. */
     964    {
     965        if (pStream->pPair)
     966        {
     967            LogRel2(("Unlinked pair '%s' from stream '%s'\n", pStream->pPair->szName, pStream->szName));
     968
     969            AssertMsg(pStream->pPair->pPair == pStream,
     970                      ("Pair '%s' is not linked to '%s' (linked to '%s')\n",
     971                       pStream->pPair->szName, pStream->szName, pStream->pPair->pPair ? pStream->pPair->pPair->szName : "<NONE>"));
     972
     973            pStream->pPair->pPair = NULL; /* Also make sure to unlink the pair from pStream */
     974            pStream->pPair = NULL;
     975        }
     976    }
     977
     978    return VINF_SUCCESS;
     979}
     980
     981/**
    987982 * @interface_method_impl{PDMIAUDIOCONNECTOR,pfnStreamPlay}
    988983 */
     
    10121007            rc = VERR_NOT_AVAILABLE;
    10131008            break;
    1014         }
    1015 
    1016         /* Backend output (temporarily) disabled / unavailable? */
    1017         if (   pThis->pHostDrvAudio->pfnGetStatus
    1018             && pThis->pHostDrvAudio->pfnGetStatus(pThis->pHostDrvAudio, PDMAUDIODIR_OUT) != PDMAUDIOBACKENDSTS_RUNNING)
    1019         {
    1020             /* Pull the new config from the backend and check again. */
    1021             rc = pThis->pHostDrvAudio->pfnGetConfig(pThis->pHostDrvAudio, &pThis->BackendCfg);
    1022             AssertRC(rc);
    1023 
    1024             if (   !pThis->BackendCfg.cSinks
    1025                 || !pThis->BackendCfg.cMaxStreamsOut)
    1026             {
    1027                 rc = VERR_NOT_AVAILABLE;
    1028                 break;
    1029             }
    10301009        }
    10311010
     
    10441023                                  rc = VERR_NOT_AVAILABLE);
    10451024
     1025        /* Is the stream scheduled for re-initialization? Do so now. */
     1026        if (pHstStream->fStatus & PDMAUDIOSTRMSTS_FLAG_PENDING_REINIT)
     1027        {
     1028            rc = drvAudioStreamReInitInternal(pThis, pStream);
     1029            if (RT_FAILURE(rc))
     1030                break;
     1031
     1032            /* On success, remove pending re-init flag. */
     1033            pHstStream->fStatus &= ~PDMAUDIOSTRMSTS_FLAG_PENDING_REINIT;
     1034        }
     1035
    10461036        AssertPtr(pThis->pHostDrvAudio->pfnStreamGetStatus);
    10471037        PDMAUDIOSTRMSTS strmSts = pThis->pHostDrvAudio->pfnStreamGetStatus(pThis->pHostDrvAudio, pHstStream);
    1048         if (!(strmSts & PDMAUDIOSTRMSTS_FLAG_INITIALIZED))
    1049         {
    1050             LogFunc(("[%s] Backend not initialized (anymore), re-initializing ...\n", pHstStream->szName));
    1051             rc = drvAudioStreamReInitInternal(pThis, pStream);
    1052             if (RT_FAILURE(rc))
    1053             {
    1054                 LogFunc(("[%s] Failed to re-initialize backend, rc=%Rrc\n", pHstStream->szName, rc));
    1055                 break;
    1056             }
    1057         }
    10581038
    10591039        uint32_t cSamplesLive = AudioMixBufLive(&pGstStream->MixBuf);
     
    11391119    do
    11401120    {
    1141         /* Backend input (temporarily) disabled / unavailable? */
    1142         if (pThis->pHostDrvAudio->pfnGetStatus(pThis->pHostDrvAudio, PDMAUDIODIR_IN) != PDMAUDIOBACKENDSTS_RUNNING)
    1143         {
    1144             rc = pThis->pHostDrvAudio->pfnGetConfig(pThis->pHostDrvAudio, &pThis->BackendCfg);
    1145             AssertRC(rc);
    1146 
    1147             if (   !pThis->BackendCfg.cSources
    1148                 || !pThis->BackendCfg.cMaxStreamsIn)
    1149             {
    1150                 rc = VERR_NOT_AVAILABLE;
    1151                 break;
    1152             }
    1153         }
    1154 
    11551121        PPDMAUDIOSTREAM pHstStream = drvAudioGetHostStream(pStream);
    11561122        AssertPtr(pHstStream);
     
    11671133                                  rc = VERR_NOT_AVAILABLE);
    11681134
     1135        /* Is the stream scheduled for re-initialization? Do so now. */
     1136        if (pHstStream->fStatus & PDMAUDIOSTRMSTS_FLAG_PENDING_REINIT)
     1137        {
     1138            rc = drvAudioStreamReInitInternal(pThis, pStream);
     1139            if (RT_FAILURE(rc))
     1140                break;
     1141
     1142            /* On success, remove pending re-init flag. */
     1143            pHstStream->fStatus &= ~PDMAUDIOSTRMSTS_FLAG_PENDING_REINIT;
     1144        }
     1145
     1146        AssertPtr(pThis->pHostDrvAudio->pfnStreamGetStatus);
    11691147        PDMAUDIOSTRMSTS strmSts = pThis->pHostDrvAudio->pfnStreamGetStatus(pThis->pHostDrvAudio, pHstStream);
    1170         if (!(strmSts & PDMAUDIOSTRMSTS_FLAG_INITIALIZED))
    1171         {
    1172             LogFunc(("[%s] Backend not initialized (anymore), re-initializing ...\n", pHstStream->szName));
    1173             rc = drvAudioStreamReInitInternal(pThis, pStream);
    1174             break;
    1175         }
    11761148
    11771149        uint32_t cSamplesLive = AudioMixBufLive(&pGstStream->MixBuf);
     
    12171189}
    12181190
    1219 #ifdef VBOX_WITH_AUDIO_CALLBACKS
     1191#ifdef VBOX_WITH_AUDIO_DEVICE_CALLBACKS
    12201192/**
    12211193 * Duplicates an audio callback.
     
    12261198static PPDMAUDIOCALLBACK drvAudioCallbackDuplicate(PPDMAUDIOCALLBACK pCB)
    12271199{
    1228     AssertPtrReturn(pCB, VERR_INVALID_POINTER);
     1200    AssertPtrReturn(pCB, NULL);
    12291201
    12301202    PPDMAUDIOCALLBACK pCBCopy = (PPDMAUDIOCALLBACK)RTMemDup((void *)pCB, sizeof(PDMAUDIOCALLBACK));
     
    12931265        switch (pCB->enmType)
    12941266        {
    1295             case PDMAUDIOCALLBACKTYPE_INPUT:
     1267            case PDMAUDIOCBTYPE_DATA_INPUT:
    12961268                RTListAppend(&pThis->lstCBIn, &pCB->Node);
    12971269                break;
    12981270
    1299             case PDMAUDIOCALLBACKTYPE_OUTPUT:
     1271            case PDMAUDIOCBTYPE_DATA_OUTPUT:
    13001272                RTListAppend(&pThis->lstCBOut, &pCB->Node);
    13011273                break;
     
    13191291 * @interface_method_impl{PDMIAUDIOCONNECTOR,pfnCallback}
    13201292 */
    1321 static DECLCALLBACK(int) drvAudioCallback(PPDMIAUDIOCONNECTOR pInterface, PDMAUDIOCALLBACKTYPE enmType,
     1293static DECLCALLBACK(int) drvAudioCallback(PPDMIAUDIOCONNECTOR pInterface, PDMAUDIOCBTYPE enmType,
    13221294                                          void *pvUser, size_t cbUser)
    13231295{
     
    13311303    switch (enmType)
    13321304    {
    1333         case PDMAUDIOCALLBACKTYPE_INPUT:
     1305        case PDMAUDIOCBTYPE_DATA_INPUT:
    13341306            pListAnchor = &pThis->lstCBIn;
    13351307            break;
    13361308
    1337         case PDMAUDIOCALLBACKTYPE_OUTPUT:
     1309        case PDMAUDIOCBTYPE_DATA_OUTPUT:
    13381310            pListAnchor = &pThis->lstCBOut;
    13391311            break;
     
    13501322        {
    13511323            Assert(pCB->enmType == enmType);
    1352             pCB->pfnCallback(enmType, pCB->pvCtx, pCB->cbCtx, pvUser, cbUser);
    1353         }
    1354     }
    1355 
    1356     return VINF_SUCCESS;
    1357 }
    1358 #endif
     1324            int rc2 = pCB->pfnCallback(enmType, pCB->pvCtx, pCB->cbCtx, pvUser, cbUser);
     1325            if (RT_FAILURE(rc2))
     1326                LogFunc(("Failed with %Rrc\n", rc2));
     1327        }
     1328
     1329        return VINF_SUCCESS;
     1330    }
     1331
     1332    return VERR_NOT_SUPPORTED;
     1333}
     1334#endif /* VBOX_WITH_AUDIO_DEVICE_CALLBACKS */
     1335
     1336#ifdef VBOX_WITH_AUDIO_CALLBACKS
     1337/**
     1338 * Backend callback implementation.
     1339 *
     1340 * Important: No calls back to the backend within this function, as the backend
     1341 *            might hold any locks / critical sections while executing this callback.
     1342 *            Will result in some ugly deadlocks then.
     1343 *
     1344 * @copydoc FNPDMHOSTAUDIOCALLBACK
     1345 */
     1346static DECLCALLBACK(int) drvAudioBackendCallback(PPDMDRVINS pDrvIns,
     1347                                                 PDMAUDIOCBTYPE enmType, void *pvUser, size_t cbUser)
     1348{
     1349    AssertPtrReturn(pDrvIns, VERR_INVALID_POINTER);
     1350    RT_NOREF(pvUser, cbUser);
     1351    /* pvUser and cbUser are optional. */
     1352
     1353    /* Get the upper driver (PDMIAUDIOCONNECTOR). */
     1354    AssertPtr(pDrvIns->pUpBase);
     1355    PPDMIAUDIOCONNECTOR pInterface = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIAUDIOCONNECTOR);
     1356    AssertPtr(pInterface);
     1357    PDRVAUDIO           pThis      = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
     1358
     1359    int rc = RTCritSectEnter(&pThis->CritSect);
     1360    AssertRCReturn(rc, rc);
     1361
     1362    LogFunc(("pThis=%p, enmType=%RU32, pvUser=%p, cbUser=%zu\n", pThis, enmType, pvUser, cbUser));
     1363
     1364    switch (enmType)
     1365    {
     1366        case PDMAUDIOCBTYPE_DEVICES_CHANGED:
     1367            LogRel(("Audio: Host audio device configuration has changed\n"));
     1368            rc = drvAudioScheduleReInit(pThis);
     1369            break;
     1370
     1371        default:
     1372            AssertMsgFailed(("Not supported\n"));
     1373            break;
     1374    }
     1375
     1376    int rc2 = RTCritSectLeave(&pThis->CritSect);
     1377    if (RT_SUCCESS(rc))
     1378        rc = rc2;
     1379
     1380    LogFlowFunc(("Returning %Rrc\n", rc));
     1381    return rc;
     1382}
     1383#endif /* VBOX_WITH_AUDIO_CALLBACKS */
    13591384
    13601385/**
     
    13871412    }
    13881413
    1389     /* Get the configuration data from backend. */
     1414    /*
     1415     * Get the backend configuration.
     1416     */
    13901417    rc = pThis->pHostDrvAudio->pfnGetConfig(pThis->pHostDrvAudio, &pThis->BackendCfg);
    13911418    if (RT_FAILURE(rc))
     
    13951422    }
    13961423
    1397     pThis->cStreamsFreeIn  = 0;
    1398     pThis->cStreamsFreeOut = 0;
    1399 
    1400     if (pThis->BackendCfg.cSinks)
    1401     {
    1402         Assert(pThis->BackendCfg.cbStreamOut);
    1403 
    1404         pThis->cStreamsFreeOut = pThis->BackendCfg.cMaxStreamsOut;
    1405     }
    1406 
    1407     if (pThis->BackendCfg.cSources)
    1408     {
    1409         Assert(pThis->BackendCfg.cbStreamIn);
    1410 
    1411         pThis->cStreamsFreeIn = pThis->BackendCfg.cMaxStreamsIn;
    1412     }
     1424    pThis->cStreamsFreeIn  = pThis->BackendCfg.cMaxStreamsIn;
     1425    pThis->cStreamsFreeOut = pThis->BackendCfg.cMaxStreamsOut;
    14131426
    14141427    LogFlowFunc(("cStreamsFreeIn=%RU8, cStreamsFreeOut=%RU8\n", pThis->cStreamsFreeIn, pThis->cStreamsFreeOut));
     
    14181431             RT_MIN(64, pThis->cStreamsFreeIn), RT_MIN(64, pThis->cStreamsFreeOut)));
    14191432
     1433    /*
     1434     * If the backend supports it, do a device enumeration.
     1435     */
     1436    bool fLog = true;
     1437
     1438    if (pThis->pHostDrvAudio->pfnGetDevices)
     1439    {
     1440        PDMAUDIODEVICEENUM DevEnum;
     1441        int rc2 = pThis->pHostDrvAudio->pfnGetDevices(pThis->pHostDrvAudio, &DevEnum);
     1442        if (RT_SUCCESS(rc2))
     1443        {
     1444            if (fLog)
     1445                LogRel(("Audio: Found %RU16 devices\n", DevEnum.cDevices));
     1446
     1447            PPDMAUDIODEVICE pDev;
     1448            RTListForEach(&DevEnum.lstDevices, pDev, PDMAUDIODEVICE, Node)
     1449            {
     1450                if (fLog)
     1451                {
     1452                    char *pszFlags = DrvAudioHlpAudDevFlagsToStrA(pDev->fFlags);
     1453
     1454                    LogRel(("Audio: Device '%s':\n", pDev->szName));
     1455                    LogRel(("Audio: \tUsage           = %s\n",   DrvAudioHlpAudDirToStr(pDev->enmUsage)));
     1456                    LogRel(("Audio: \tFlags           = %s\n",   pszFlags ? pszFlags : "<NONE>"));
     1457                    LogRel(("Audio: \tInput channels  = %RU8\n", pDev->cMaxInputChannels));
     1458                    LogRel(("Audio: \tOutput channels = %RU8\n", pDev->cMaxOutputChannels));
     1459
     1460                    if (pszFlags)
     1461                        RTStrFree(pszFlags);
     1462                }
     1463            }
     1464
     1465            DrvAudioHlpDeviceEnumFree(&DevEnum);
     1466        }
     1467        else
     1468        {
     1469            LogRel2(("Audio: Device enumeration failed with %Rrc\n", rc2));
     1470            /* Not fatal. */
     1471        }
     1472    }
     1473
     1474#ifdef VBOX_WITH_AUDIO_CALLBACKS
     1475    /*
     1476     * If the backend supports it, offer a callback to this connector.
     1477     */
     1478    if (pThis->pHostDrvAudio->pfnSetCallback)
     1479    {
     1480        int rc2 = pThis->pHostDrvAudio->pfnSetCallback(pThis->pHostDrvAudio, drvAudioBackendCallback);
     1481        if (RT_FAILURE(rc2))
     1482             LogRel(("Audio: Error registering backend callback, rc=%Rrc\n", rc2));
     1483        /* Not fatal. */
     1484    }
     1485#endif
     1486
    14201487    LogFlowFuncLeave();
    14211488    return VINF_SUCCESS;
     
    14611528
    14621529    int rc = RTCritSectInit(&pThis->CritSect);
     1530    AssertRCReturn(rc, rc);
    14631531
    14641532    /** @todo Add audio driver options. */
     
    14671535     * If everything went well, initialize the lower driver.
    14681536     */
    1469     if (RT_SUCCESS(rc))
    1470         rc = drvAudioHostInit(pThis, pCfgHandle);
     1537    rc = drvAudioHostInit(pThis, pCfgHandle);
    14711538
    14721539    LogFlowFuncLeaveRC(rc);
     
    16701737                    strlen(pCfgHost->szName) ? pCfgHost->szName : "<Untitled>");
    16711738
    1672         pHstStrm->pPair = pGstStrm;
     1739        rc = drvAudioStreamLinkToInternal(pHstStrm, pGstStrm);
     1740        AssertRCBreak(rc);
    16731741
    16741742        /*
     
    16791747
    16801748        pGstStrm->fStatus = pHstStrm->fStatus; /* Reflect the host stream's status. */
    1681         pGstStrm->pPair   = pHstStrm;
     1749
     1750        rc = drvAudioStreamLinkToInternal(pGstStrm, pHstStrm);
     1751        AssertRCBreak(rc);
    16821752
    16831753        /*
     
    16911761        }
    16921762
     1763#ifdef VBOX_WITH_STATISTICS
     1764        char szStatName[255];
     1765
     1766        if (pCfgGuest->enmDir == PDMAUDIODIR_IN)
     1767        {
     1768            RTStrPrintf(szStatName, sizeof(szStatName), "Guest/%s/BytesElapsed", pGstStrm->szName);
     1769            PDMDrvHlpSTAMRegCounterEx(pThis->pDrvIns, &pGstStrm->In.StatBytesElapsed,
     1770                                      szStatName, STAMUNIT_BYTES, "Elapsed bytes read.");
     1771
     1772            RTStrPrintf(szStatName, sizeof(szStatName), "Guest/%s/BytesRead", pGstStrm->szName);
     1773            PDMDrvHlpSTAMRegCounterEx(pThis->pDrvIns, &pGstStrm->In.StatBytesTotalRead,
     1774                                      szStatName, STAMUNIT_BYTES, "Total bytes read.");
     1775
     1776            RTStrPrintf(szStatName, sizeof(szStatName), "Host/%s/SamplesCaptured", pHstStrm->szName);
     1777            PDMDrvHlpSTAMRegCounterEx(pThis->pDrvIns, &pHstStrm->In.StatSamplesCaptured,
     1778                                      szStatName, STAMUNIT_COUNT, "Total samples captured.");
     1779        }
     1780        else if (pCfgGuest->enmDir == PDMAUDIODIR_OUT)
     1781        {
     1782            RTStrPrintf(szStatName, sizeof(szStatName), "Guest/%s/BytesElapsed", pGstStrm->szName);
     1783            PDMDrvHlpSTAMRegCounterEx(pThis->pDrvIns, &pGstStrm->Out.StatBytesElapsed,
     1784                                      szStatName, STAMUNIT_BYTES, "Elapsed bytes written.");
     1785
     1786            RTStrPrintf(szStatName, sizeof(szStatName), "Guest/%s/BytesRead", pGstStrm->szName);
     1787            PDMDrvHlpSTAMRegCounterEx(pThis->pDrvIns, &pGstStrm->Out.StatBytesTotalWritten,
     1788                                      szStatName, STAMUNIT_BYTES, "Total bytes written.");
     1789
     1790            RTStrPrintf(szStatName, sizeof(szStatName), "Host/%s/SamplesPlayed", pHstStrm->szName);
     1791            PDMDrvHlpSTAMRegCounterEx(pThis->pDrvIns, &pHstStrm->Out.StatSamplesPlayed,
     1792                                      szStatName, STAMUNIT_COUNT, "Total samples played.");
     1793        }
     1794#endif
     1795
    16931796    } while (0);
    16941797
     
    19822085            if (RT_SUCCESS(rc))
    19832086            {
     2087#ifdef VBOX_WITH_STATISTICS
     2088                if (pHstStream->enmDir == PDMAUDIODIR_IN)
     2089                {
     2090                    PDMDrvHlpSTAMDeregister(pThis->pDrvIns, &pHstStream->In.StatSamplesCaptured);
     2091                }
     2092                else if (pHstStream->enmDir == PDMAUDIODIR_OUT)
     2093                {
     2094                    PDMDrvHlpSTAMDeregister(pThis->pDrvIns, &pHstStream->Out.StatSamplesPlayed);
     2095                }
     2096#endif
    19842097                RTListNodeRemove(&pHstStream->Node);
    19852098
     
    19972110            if (RT_SUCCESS(rc))
    19982111            {
     2112#ifdef VBOX_WITH_STATISTICS
     2113                if (pGstStream->enmDir == PDMAUDIODIR_IN)
     2114                {
     2115                    PDMDrvHlpSTAMDeregister(pThis->pDrvIns, &pGstStream->In.StatBytesElapsed);
     2116                    PDMDrvHlpSTAMDeregister(pThis->pDrvIns, &pGstStream->In.StatBytesTotalRead);
     2117                }
     2118                else if (pGstStream->enmDir == PDMAUDIODIR_OUT)
     2119                {
     2120                    PDMDrvHlpSTAMDeregister(pThis->pDrvIns, &pGstStream->Out.StatBytesElapsed);
     2121                    PDMDrvHlpSTAMDeregister(pThis->pDrvIns, &pGstStream->Out.StatBytesTotalWritten);
     2122                }
     2123#endif
    19992124                RTListNodeRemove(&pGstStream->Node);
    20002125
     
    20282153
    20292154/**
     2155 * Creates an audio stream on the backend side.
     2156 *
     2157 * @returns IPRT status code.
     2158 * @param   pThis               Pointer to driver instance.
     2159 * @param   pHstStream          (Host) audio stream to use for creating the stream on the backend side.
     2160 * @param   pCfgReq             Requested audio stream configuration to use for stream creation.
     2161 * @param   pCfgAcq             Acquired audio stream configuration returned by the backend. Optional, can be NULL.
     2162 */
     2163static int drvAudioStreamCreateInternalBackend(PDRVAUDIO pThis,
     2164                                               PPDMAUDIOSTREAM pHstStream, PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
     2165{
     2166    AssertPtrReturn(pThis,      VERR_INVALID_POINTER);
     2167    AssertPtrReturn(pHstStream, VERR_INVALID_POINTER);
     2168    AssertPtrReturn(pCfgReq,    VERR_INVALID_POINTER);
     2169    /* pCfgAcq is optional. */
     2170
     2171    AssertMsg(pHstStream->enmCtx == PDMAUDIOSTREAMCTX_HOST,
     2172              ("Stream '%s' is not a host stream and therefore has no backend\n", pHstStream->szName));
     2173
     2174    AssertMsg((pHstStream->fStatus & PDMAUDIOSTRMSTS_FLAG_INITIALIZED) == 0,
     2175              ("Stream '%s' already initialized in backend\n", pHstStream->szName));
     2176
     2177    PDMAUDIOSTREAMCFG CfgAcq;
     2178
     2179    /* Make the acquired host configuration the requested host configuration initially,
     2180     * in case the backend does not report back an acquired configuration. */
     2181    memcpy(&CfgAcq, pCfgReq, sizeof(PDMAUDIOSTREAMCFG));
     2182
     2183    int rc = pThis->pHostDrvAudio->pfnStreamCreate(pThis->pHostDrvAudio, pHstStream, pCfgReq, &CfgAcq);
     2184    if (RT_FAILURE(rc))
     2185    {
     2186        LogRel2(("Audio: Creating stream '%s' in backend failed with %Rrc\n", pHstStream->szName, rc));
     2187        return rc;
     2188    }
     2189
     2190    /* Validate acquired configuration. */
     2191    if (!DrvAudioHlpStreamCfgIsValid(&CfgAcq))
     2192    {
     2193        LogRel2(("Audio: Creating stream '%s' has an invalid configuration, skipping\n", pHstStream->szName));
     2194        return VERR_INVALID_PARAMETER;
     2195    }
     2196
     2197    /* Only set the host's stream to initialized if we were able create the stream
     2198     * in the host backend. This is necessary for trying to re-initialize the stream
     2199     * at some later point in time. */
     2200    pHstStream->fStatus |= PDMAUDIOSTRMSTS_FLAG_INITIALIZED;
     2201
     2202    if (pCfgAcq)
     2203        memcpy(pCfgAcq, &CfgAcq, sizeof(PDMAUDIOSTREAMCFG));
     2204
     2205    return VINF_SUCCESS;
     2206}
     2207
     2208/**
    20302209 * Calls the backend to give it the chance to destroy its part of the audio stream.
    20312210 *
     
    20342213 * @param   pHstStream          Host audio stream to call the backend destruction for.
    20352214 */
    2036 static int drvAudioStreamDestroyInBackendInternal(PDRVAUDIO pThis, PPDMAUDIOSTREAM pHstStream)
     2215static int drvAudioStreamDestroyInternalBackend(PDRVAUDIO pThis, PPDMAUDIOSTREAM pHstStream)
    20372216{
    20382217    AssertPtrReturn(pThis,      VERR_INVALID_POINTER);
     
    20872266                pStream->fStatus &= ~PDMAUDIOSTRMSTS_FLAG_INITIALIZED;
    20882267        }
    2089 
    2090         if (pStream->enmDir == PDMAUDIODIR_IN)
    2091         {
    2092 #ifdef VBOX_WITH_STATISTICS
    2093             PDMDrvHlpSTAMDeregister(pThis->pDrvIns, &pStream->In.StatBytesElapsed);
    2094             PDMDrvHlpSTAMDeregister(pThis->pDrvIns, &pStream->In.StatBytesTotalRead);
    2095 #endif
    2096         }
    2097         else if (pStream->enmDir == PDMAUDIODIR_OUT)
    2098         {
    2099 #ifdef VBOX_WITH_STATISTICS
    2100             PDMDrvHlpSTAMDeregister(pThis->pDrvIns, &pStream->Out.StatBytesElapsed);
    2101             PDMDrvHlpSTAMDeregister(pThis->pDrvIns, &pStream->Out.StatBytesTotalWritten);
    2102 #endif
    2103         }
    21042268    }
    21052269    else if (pStream->enmCtx == PDMAUDIOSTREAMCTX_HOST)
    21062270    {
    2107         rc = drvAudioStreamDestroyInBackendInternal(pThis, pStream);
    2108 
    2109         if (pStream->enmDir == PDMAUDIODIR_IN)
    2110         {
    2111 #ifdef VBOX_WITH_STATISTICS
    2112             PDMDrvHlpSTAMDeregister(pThis->pDrvIns, &pStream->In.StatSamplesCaptured);
    2113 #endif
    2114         }
    2115         else if (pStream->enmDir == PDMAUDIODIR_OUT)
    2116         {
    2117 #ifdef VBOX_WITH_STATISTICS
    2118             PDMDrvHlpSTAMDeregister(pThis->pDrvIns, &pStream->Out.StatSamplesPlayed);
    2119 #endif
    2120         }
     2271        rc = drvAudioStreamDestroyInternalBackend(pThis, pStream);
    21212272    }
    21222273    else
     
    21262277    {
    21272278        /* Make sure that the pair (if any) knows that we're not valid anymore. */
    2128         if (pStream->pPair)
    2129             pStream->pPair->pPair = NULL;
     2279        int rc2 = drvAudioStreamLinkToInternal(pStream, NULL);
     2280        AssertRC(rc2);
    21302281
    21312282        /* Reset status. */
    21322283        pStream->fStatus = PDMAUDIOSTRMSTS_FLAG_NONE;
    2133 
    2134         /* Clear name. */
    2135         pStream->szName[0] = '\0';
    21362284
    21372285        /* Destroy mixing buffer. */
     
    21772325    PPDMAUDIOSTREAM pStream;
    21782326    RTListForEach(&pThis->lstHstStreams, pStream, PDMAUDIOSTREAM, Node)
    2179         drvAudioStreamDestroyInBackendInternal(pThis, pStream);
     2327        drvAudioStreamDestroyInternalBackend(pThis, pStream);
    21802328
    21812329    /*
     
    22052353    RTListInit(&pThis->lstHstStreams);
    22062354    RTListInit(&pThis->lstGstStreams);
    2207 #ifdef VBOX_WITH_AUDIO_CALLBACKS
     2355#ifdef VBOX_WITH_AUDIO_DEVICE_CALLBACKS
    22082356    RTListInit(&pThis->lstCBIn);
    22092357    RTListInit(&pThis->lstCBOut);
     
    22332381    pThis->IAudioConnector.pfnStreamPlay        = drvAudioStreamPlay;
    22342382    pThis->IAudioConnector.pfnStreamCapture     = drvAudioStreamCapture;
    2235 #ifdef VBOX_WITH_AUDIO_CALLBACKS
     2383#ifdef VBOX_WITH_AUDIO_DEVICE_CALLBACKS
    22362384    pThis->IAudioConnector.pfnRegisterCallbacks = drvAudioRegisterCallbacks;
    22372385    pThis->IAudioConnector.pfnCallback          = drvAudioCallback;
     
    23412489    Assert(RTListIsEmpty(&pThis->lstGstStreams));
    23422490
    2343 #ifdef VBOX_WITH_AUDIO_CALLBACKS
     2491#ifdef VBOX_WITH_AUDIO_DEVICE_CALLBACKS
    23442492    /*
    2345      * Destroy callbacks, if any.
     2493     * Destroy device callbacks, if any.
    23462494     */
    23472495    PPDMAUDIOCALLBACK pCB, pCBNext;
  • trunk/src/VBox/Devices/Audio/DrvAudio.h

    r63362 r63711  
    120120    /** Audio configuration settings retrieved from the backend. */
    121121    PDMAUDIOBACKENDCFG      BackendCfg;
    122 #ifdef VBOX_WITH_AUDIO_CALLBACKS
     122#ifdef VBOX_WITH_AUDIO_DEVICE_CALLBACKS
    123123    /** @todo Use a map with primary key set to the callback type? */
    124124    RTLISTANCHOR            lstCBIn;
     
    154154int DrvAudioHlpGetFileName(char *pszFile, size_t cchFile, const char *pszPath, const char *pszName, PDMAUDIOFILETYPE enmType);
    155155
     156PPDMAUDIODEVICE DrvAudioHlpDeviceAlloc(size_t cbData);
     157void DrvAudioHlpDeviceFree(PPDMAUDIODEVICE pDev);
     158
     159int DrvAudioHlpDeviceEnumInit(PPDMAUDIODEVICEENUM pDevEnm);
     160void DrvAudioHlpDeviceEnumFree(PPDMAUDIODEVICEENUM pDevEnm);
     161int DrvAudioHlpDeviceEnumAdd(PPDMAUDIODEVICEENUM pDevEnm, PPDMAUDIODEVICE pDev);
     162PPDMAUDIODEVICE DrvAudioHlpDeviceEnumGetDefaultDevice(PPDMAUDIODEVICEENUM pDevEnm, PDMAUDIODIR enmDir);
     163void DrvAudioHlpDeviceEnumPrint(const char *pszDesc, PPDMAUDIODEVICEENUM pDevEnm);
     164
     165const char *DrvAudioHlpAudDirToStr(PDMAUDIODIR enmDir);
     166char *DrvAudioHlpAudDevFlagsToStrA(PDMAUDIODEVFLAG fFlags);
     167
    156168int DrvAudioHlpWAVFileOpen(PPDMAUDIOFILE pFile, const char *pszFile, uint32_t fOpen, PPDMAUDIOPCMPROPS pProps, PDMAUDIOFILEFLAGS fFlags);
    157169int DrvAudioHlpWAVFileClose(PPDMAUDIOFILE pFile);
  • trunk/src/VBox/Devices/Audio/DrvAudioCommon.cpp

    r63362 r63711  
    5050#include <iprt/uuid.h>
    5151
     52#define LOG_GROUP LOG_GROUP_DRV_AUDIO
     53#include <VBox/log.h>
     54
     55#include <VBox/err.h>
    5256#include <VBox/vmm/pdmdev.h>
    5357#include <VBox/vmm/pdm.h>
    54 #include <VBox/err.h>
    5558#include <VBox/vmm/mm.h>
    5659
     
    200203        }
    201204    }
     205}
     206
     207/**
     208 * Allocates an audio device.
     209 *
     210 * @returns Newly allocated audio device, or NULL if failed.
     211 * @param   cbData              How much additional data (in bytes) should be allocated to provide
     212 *                              a (backend) specific area to store additional data.
     213 *                              Optional, can be 0.
     214 */
     215PPDMAUDIODEVICE DrvAudioHlpDeviceAlloc(size_t cbData)
     216{
     217    PPDMAUDIODEVICE pDev = (PPDMAUDIODEVICE)RTMemAllocZ(sizeof(PDMAUDIODEVICE));
     218    if (!pDev)
     219        return NULL;
     220
     221    if (cbData)
     222    {
     223        pDev->pvData = RTMemAlloc(cbData);
     224        if (!pDev->pvData)
     225        {
     226            RTMemFree(pDev);
     227            return NULL;
     228        }
     229    }
     230
     231    pDev->cbData = cbData;
     232
     233    pDev->cMaxInputChannels  = 0;
     234    pDev->cMaxOutputChannels = 0;
     235
     236    return pDev;
     237}
     238
     239/**
     240 * Frees an audio device.
     241 *
     242 * @param pDev                  Device to free.
     243 */
     244void DrvAudioHlpDeviceFree(PPDMAUDIODEVICE pDev)
     245{
     246    if (!pDev)
     247        return;
     248
     249    Assert(pDev->cRefCount == 0);
     250
     251    if (pDev->pvData)
     252    {
     253        Assert(pDev->cbData);
     254
     255        RTMemFree(pDev->pvData);
     256    }
     257
     258    RTMemFree(pDev);
     259}
     260
     261/**
     262 * Initializes an audio device enumeration structure.
     263 *
     264 * @returns IPRT status code.
     265 * @param   pDevEnm             Device enumeration to initialize.
     266 */
     267int DrvAudioHlpDeviceEnumInit(PPDMAUDIODEVICEENUM pDevEnm)
     268{
     269    AssertPtrReturn(pDevEnm, VERR_INVALID_POINTER);
     270
     271    RTListInit(&pDevEnm->lstDevices);
     272    pDevEnm->cDevices = 0;
     273
     274    return VINF_SUCCESS;
     275}
     276
     277/**
     278 * Frees audio device enumeration data.
     279 *
     280 * @param pDevEnm               Device enumeration to destroy.
     281 */
     282void DrvAudioHlpDeviceEnumFree(PPDMAUDIODEVICEENUM pDevEnm)
     283{
     284    if (!pDevEnm)
     285        return;
     286
     287    PPDMAUDIODEVICE pDev, pDevNext;
     288    RTListForEachSafe(&pDevEnm->lstDevices, pDev, pDevNext, PDMAUDIODEVICE, Node)
     289    {
     290        RTListNodeRemove(&pDev->Node);
     291
     292        DrvAudioHlpDeviceFree(pDev);
     293
     294        pDevEnm->cDevices--;
     295    }
     296
     297    /* Sanity. */
     298    Assert(RTListIsEmpty(&pDevEnm->lstDevices));
     299    Assert(pDevEnm->cDevices == 0);
     300}
     301
     302/**
     303 * Adds an audio device to a device enumeration.
     304 *
     305 * @return IPRT status code.
     306 * @param  pDevEnm              Device enumeration to add device to.
     307 * @param  pDev                 Device to add.
     308 */
     309int DrvAudioHlpDeviceEnumAdd(PPDMAUDIODEVICEENUM pDevEnm, PPDMAUDIODEVICE pDev)
     310{
     311    AssertPtrReturn(pDevEnm, VERR_INVALID_POINTER);
     312    AssertPtrReturn(pDev,    VERR_INVALID_POINTER);
     313
     314    RTListAppend(&pDevEnm->lstDevices, &pDev->Node);
     315    pDevEnm->cDevices++;
     316
     317    return VINF_SUCCESS;
     318}
     319
     320/**
     321 * Returns the default device of a given device enumeration.
     322 * This assumes that only one default device per usage is set.
     323 *
     324 * @returns Default device if found, or NULL if none found.
     325 * @param   pDevEnm             Device enumeration to get default device for.
     326 * @param   enmUsage            Usage to get default device for.
     327 */
     328PPDMAUDIODEVICE DrvAudioHlpDeviceEnumGetDefaultDevice(PPDMAUDIODEVICEENUM pDevEnm, PDMAUDIODIR enmUsage)
     329{
     330    AssertPtrReturn(pDevEnm, NULL);
     331
     332    PPDMAUDIODEVICE pDev;
     333    RTListForEach(&pDevEnm->lstDevices, pDev, PDMAUDIODEVICE, Node)
     334    {
     335        if (enmUsage != PDMAUDIODIR_ANY)
     336        {
     337            if (enmUsage != pDev->enmUsage) /* Wrong usage? Skip. */
     338                continue;
     339        }
     340
     341        if (pDev->fFlags & PDMAUDIODEV_FLAGS_DEFAULT)
     342            return pDev;
     343    }
     344
     345    return NULL;
     346}
     347
     348/**
     349 * Logs an audio device enumeration.
     350 *
     351 * @param  pszDesc              Logging description.
     352 * @param  pDevEnm              Device enumeration to log.
     353 */
     354void DrvAudioHlpDeviceEnumPrint(const char *pszDesc, PPDMAUDIODEVICEENUM pDevEnm)
     355{
     356    AssertPtrReturnVoid(pszDesc);
     357    AssertPtrReturnVoid(pDevEnm);
     358
     359    LogFunc(("%s: %RU16 devices\n", pszDesc, pDevEnm->cDevices));
     360
     361    PPDMAUDIODEVICE pDev;
     362    RTListForEach(&pDevEnm->lstDevices, pDev, PDMAUDIODEVICE, Node)
     363    {
     364        char *pszFlags = DrvAudioHlpAudDevFlagsToStrA(pDev->fFlags);
     365
     366        LogFunc(("Device '%s':\n", pDev->szName));
     367        LogFunc(("\tUsage           = %s\n",             DrvAudioHlpAudDirToStr(pDev->enmUsage)));
     368        LogFunc(("\tFlags           = %s\n",             pszFlags ? pszFlags : "<NONE>"));
     369        LogFunc(("\tInput channels  = %RU8\n",           pDev->cMaxInputChannels));
     370        LogFunc(("\tOutput channels = %RU8\n",           pDev->cMaxOutputChannels));
     371        LogFunc(("\tData            = %p (%zu bytes)\n", pDev->pvData, pDev->cbData));
     372
     373        if (pszFlags)
     374            RTStrFree(pszFlags);
     375    }
     376}
     377
     378/**
     379 * Converts an audio direction to a string.
     380 *
     381 * @returns Stringified audio direction, or "Unknown", if not found.
     382 * @param   enmDir              Audio direction to convert.
     383 */
     384const char *DrvAudioHlpAudDirToStr(PDMAUDIODIR enmDir)
     385{
     386    switch (enmDir)
     387    {
     388        case PDMAUDIODIR_UNKNOWN: return "Unknown";
     389        case PDMAUDIODIR_IN:      return "Input";
     390        case PDMAUDIODIR_OUT:     return "Output";
     391        case PDMAUDIODIR_ANY:     return "Duplex";
     392        default:                  break;
     393    }
     394
     395    AssertMsgFailed(("Invalid audio direction %ld\n", enmDir));
     396    return "Unknown";
     397}
     398
     399/**
     400 * Converts an audio device flags to a string.
     401 *
     402 * @returns Stringified audio flags. Must be free'd with RTStrFree().
     403 *          NULL if no flags set.
     404 * @param   fFlags              Audio flags to convert.
     405 */
     406char *DrvAudioHlpAudDevFlagsToStrA(PDMAUDIODEVFLAG fFlags)
     407{
     408
     409#define APPEND_FLAG_TO_STR(_aFlag)              \
     410    if (fFlags & PDMAUDIODEV_FLAGS_##_aFlag)    \
     411    {                                           \
     412        if (pszFlags)                           \
     413        {                                       \
     414            rc2 = RTStrAAppend(&pszFlags, " "); \
     415            if (RT_FAILURE(rc2))                \
     416                break;                          \
     417        }                                       \
     418                                                \
     419        rc2 = RTStrAAppend(&pszFlags, #_aFlag); \
     420        if (RT_FAILURE(rc2))                    \
     421            break;                              \
     422    }                                           \
     423
     424    char *pszFlags = NULL;
     425    int rc2;
     426
     427    do
     428    {
     429        APPEND_FLAG_TO_STR(DEFAULT);
     430        APPEND_FLAG_TO_STR(HOTPLUG);
     431        APPEND_FLAG_TO_STR(BUGGY);
     432        APPEND_FLAG_TO_STR(IGNORE);
     433
     434    } while (0);
     435
     436    if (   RT_FAILURE(rc2)
     437        && pszFlags)
     438    {
     439        RTStrFree(pszFlags);
     440        pszFlags = NULL;
     441    }
     442
     443#undef APPEND_FLAG_TO_STR
     444
     445    return pszFlags;
    202446}
    203447
     
    346590        return PDMAUDIOFMT_S32;
    347591
    348     AssertMsgFailed(("Invalid audio format \"%s\"\n", pszFmt));
     592    AssertMsgFailed(("Invalid audio format '%s'\n", pszFmt));
    349593    return PDMAUDIOFMT_INVALID;
    350594}
  • trunk/src/VBox/Devices/Audio/DrvHostALSAAudio.cpp

    r63534 r63711  
    15331533    pBackendCfg->cbStreamOut = sizeof(ALSAAUDIOSTREAMOUT);
    15341534
    1535     pBackendCfg->cSources    = 0;
    1536     pBackendCfg->cSinks      = 0;
    1537 
    15381535    /* Enumerate sound devices. */
    15391536    char **pszHints;
     
    15581555            if (pszIOID)
    15591556            {
     1557#if 0
    15601558                if (!RTStrICmp("input", pszIOID))
    1561                     pBackendCfg->cSources++;
     1559
    15621560                else if (!RTStrICmp("output", pszIOID))
    1563                     pBackendCfg->cSinks++;
     1561#endif
    15641562            }
    15651563            else /* NULL means bidirectional, input + output. */
    15661564            {
    1567                 pBackendCfg->cSources++;
    1568                 pBackendCfg->cSinks++;
    15691565            }
    15701566
     
    15841580            pszHintCur++;
    15851581        }
    1586 
    1587         LogRel2(("ALSA: Found %RU8 host playback devices\n",  pBackendCfg->cSinks));
    1588         LogRel2(("ALSA: Found %RU8 host capturing devices\n", pBackendCfg->cSources));
    15891582
    15901583        snd_device_name_free_hint((void **)pszHints);
  • trunk/src/VBox/Devices/Audio/DrvHostCoreAudio.cpp

    r63683 r63711  
    1616 */
    1717
    18 
    1918/*********************************************************************************************************************************
    2019*   Header Files                                                                                                                 *
     
    2221#define LOG_GROUP LOG_GROUP_DRV_HOST_AUDIO
    2322#include <VBox/log.h>
    24 #include <VBox/vmm/pdmaudioifs.h>
    2523
    2624#include "DrvAudio.h"
     
    5149#endif
    5250
     51/* Enables utilizing the Core Audio converter unit for converting
     52 * input / output from/to our requested formats. That might be more
     53 * performant than using our own routines later down the road. */
     54/** @todo Needs more investigation and testing first before enabling. */
     55//# define VBOX_WITH_AUDIO_CA_CONVERTER
     56
     57#ifdef DEBUG_andy
     58# undef  DEBUG_DUMP_PCM_DATA_PATH
     59# define DEBUG_DUMP_PCM_DATA_PATH "/Users/anloeffl/Documents/"
     60# undef  VBOX_WITH_AUDIO_CA_CONVERTER
     61#endif
     62
    5363/** @todo
    5464 * - Maybe make sure the threads are immediately stopped if playing/recording stops.
     
    6474 */
    6575
     76/* Prototypes needed for COREAUDIODEVICE. */
     77struct DRVHOSTCOREAUDIO;
     78typedef struct DRVHOSTCOREAUDIO *PDRVHOSTCOREAUDIO;
     79
     80/**
     81 * Structure for holding Core Audio-specific device data.
     82 * This data then lives in the pvData part of the PDMAUDIODEVICE struct.
     83 */
     84typedef struct COREAUDIODEVICEDATA
     85{
     86    /** Pointer to driver instance this device is bound to. */
     87    PDRVHOSTCOREAUDIO pDrv;
     88    /** The audio device ID of the currently used device. */
     89    AudioDeviceID     deviceID;
     90    /** List of attached (native) Core Audio streams attached to this device. */
     91    RTLISTANCHOR      lstStreams;
     92} COREAUDIODEVICEDATA, *PCOREAUDIODEVICEDATA;
     93
     94/**
     95 * Host Coreaudio driver instance data.
     96 * @implements PDMIAUDIOCONNECTOR
     97 */
     98typedef struct DRVHOSTCOREAUDIO
     99{
     100    /** Pointer to the driver instance structure. */
     101    PPDMDRVINS              pDrvIns;
     102    /** Pointer to host audio interface. */
     103    PDMIHOSTAUDIO           IHostAudio;
     104    /** Critical section to serialize access. */
     105    RTCRITSECT              CritSect;
     106    /** Current (last reported) device enumeration. */
     107    PDMAUDIODEVICEENUM      Devices;
     108    /** Pointer to the currently used input device in the device enumeration.
     109     *  Can be NULL if none assigned. */
     110    PPDMAUDIODEVICE         pDefaultDevIn;
     111    /** Pointer to the currently used output device in the device enumeration.
     112     *  Can be NULL if none assigned. */
     113    PPDMAUDIODEVICE         pDefaultDevOut;
     114#ifdef VBOX_WITH_AUDIO_CALLBACKS
     115    /** Callback function to the upper driver.
     116     *  Can be NULL if not being used / registered. */
     117    PFNPDMHOSTAUDIOCALLBACK pfnCallback;
     118#endif
     119} DRVHOSTCOREAUDIO, *PDRVHOSTCOREAUDIO;
     120
     121/** Converts a pointer to DRVHOSTCOREAUDIO::IHostAudio to a PDRVHOSTCOREAUDIO. */
     122#define PDMIHOSTAUDIO_2_DRVHOSTCOREAUDIO(pInterface) RT_FROM_MEMBER(pInterface, DRVHOSTCOREAUDIO, IHostAudio)
     123
     124/**
     125 * Structure for holding a Core Audio unit
     126 * and its data.
     127 */
     128typedef struct COREAUDIOUNIT
     129{
     130    /** Pointer to the device this audio unit is bound to.
     131     *  Can be NULL if not bound to a device (anymore). */
     132    PPDMAUDIODEVICE             pDevice;
     133    /** The actual audio unit object. */
     134    AudioUnit                   audioUnit;
     135    /** Stream description for using with VBox:
     136     *  - When using this audio unit for input (capturing), this format states
     137     *    the unit's output format.
     138     *  - When using this audio unit for output (playback), this format states
     139     *    the unit's input format. */
     140    AudioStreamBasicDescription streamFmt;
     141} COREAUDIOUNIT, *PCOREAUDIOUNIT;
    66142
    67143/*******************************************************************************
     
    77153    char pszSampleRate[32];
    78154    LogRel2(("CoreAudio: %s description:\n", pszDesc));
    79     LogRel2(("CoreAudio: Format ID: %RU32 (%c%c%c%c)\n", pASBD->mFormatID,
     155    LogRel2(("CoreAudio:\tFormat ID: %RU32 (%c%c%c%c)\n", pASBD->mFormatID,
    80156             RT_BYTE4(pASBD->mFormatID), RT_BYTE3(pASBD->mFormatID),
    81157             RT_BYTE2(pASBD->mFormatID), RT_BYTE1(pASBD->mFormatID)));
    82     LogRel2(("CoreAudio: Flags: %RU32", pASBD->mFormatFlags));
     158    LogRel2(("CoreAudio:\tFlags: %RU32", pASBD->mFormatFlags));
    83159    if (pASBD->mFormatFlags & kAudioFormatFlagIsFloat)
    84160        LogRel2((" Float"));
     
    99175    LogRel2(("\n"));
    100176    snprintf(pszSampleRate, 32, "%.2f", (float)pASBD->mSampleRate); /** @todo r=andy Use RTStrPrint*. */
    101     LogRel2(("CoreAudio: SampleRate      : %s\n", pszSampleRate));
    102     LogRel2(("CoreAudio: ChannelsPerFrame: %RU32\n", pASBD->mChannelsPerFrame));
    103     LogRel2(("CoreAudio: FramesPerPacket : %RU32\n", pASBD->mFramesPerPacket));
    104     LogRel2(("CoreAudio: BitsPerChannel  : %RU32\n", pASBD->mBitsPerChannel));
    105     LogRel2(("CoreAudio: BytesPerFrame   : %RU32\n", pASBD->mBytesPerFrame));
    106     LogRel2(("CoreAudio: BytesPerPacket  : %RU32\n", pASBD->mBytesPerPacket));
     177    LogRel2(("CoreAudio:\tSampleRate      : %s\n", pszSampleRate));
     178    LogRel2(("CoreAudio:\tChannelsPerFrame: %RU32\n", pASBD->mChannelsPerFrame));
     179    LogRel2(("CoreAudio:\tFramesPerPacket : %RU32\n", pASBD->mFramesPerPacket));
     180    LogRel2(("CoreAudio:\tBitsPerChannel  : %RU32\n", pASBD->mBitsPerChannel));
     181    LogRel2(("CoreAudio:\tBytesPerFrame   : %RU32\n", pASBD->mBytesPerFrame));
     182    LogRel2(("CoreAudio:\tBytesPerPacket  : %RU32\n", pASBD->mBytesPerPacket));
    107183}
    108184
     
    139215}
    140216
     217static int coreAudioASBDToStreamCfg(AudioStreamBasicDescription *pASBD, PPDMAUDIOSTREAMCFG pCfg)
     218{
     219    AssertPtrReturn(pASBD, VERR_INVALID_PARAMETER);
     220    AssertPtrReturn(pCfg,  VERR_INVALID_PARAMETER);
     221
     222    pCfg->cChannels     = pASBD->mChannelsPerFrame;
     223    pCfg->uHz           = (uint32_t)pASBD->mSampleRate;
     224    pCfg->enmEndianness = PDMAUDIOENDIANNESS_LITTLE;
     225
     226    int rc = VINF_SUCCESS;
     227
     228    if (pASBD->mFormatFlags & kAudioFormatFlagIsSignedInteger)
     229    {
     230        switch (pASBD->mBitsPerChannel)
     231        {
     232            case 8:  pCfg->enmFormat = PDMAUDIOFMT_S8;  break;
     233            case 16: pCfg->enmFormat = PDMAUDIOFMT_S16; break;
     234            case 32: pCfg->enmFormat = PDMAUDIOFMT_S32; break;
     235            default: rc = VERR_NOT_SUPPORTED;           break;
     236        }
     237    }
     238    else
     239    {
     240        switch (pASBD->mBitsPerChannel)
     241        {
     242            case 8:  pCfg->enmFormat = PDMAUDIOFMT_U8;  break;
     243            case 16: pCfg->enmFormat = PDMAUDIOFMT_U16; break;
     244            case 32: pCfg->enmFormat = PDMAUDIOFMT_U32; break;
     245            default: rc = VERR_NOT_SUPPORTED;           break;
     246        }
     247    }
     248
     249    AssertRC(rc);
     250    return rc;
     251}
     252
    141253static OSStatus coreAudioSetFrameBufferSize(AudioDeviceID deviceID, bool fInput, UInt32 cReqSize, UInt32 *pcActSize)
    142254{
     
    212324}
    213325
    214 DECL_FORCE_INLINE(bool) coreAudioIsRunning(AudioDeviceID deviceID)
    215 {
    216     AudioObjectPropertyAddress propAdr = { kAudioDevicePropertyDeviceIsRunning, kAudioObjectPropertyScopeGlobal,
    217                                            kAudioObjectPropertyElementMaster };
    218     UInt32 uFlag = 0;
    219     UInt32 uSize = sizeof(uFlag);
    220     OSStatus err = AudioObjectGetPropertyData(deviceID, &propAdr, 0, NULL, &uSize, &uFlag);
    221     if (err != kAudioHardwareNoError)
    222         LogRel(("CoreAudio: Could not determine whether the device is running (%RI32)\n", err));
    223 
    224     return (uFlag >= 1);
    225 }
    226 
     326#if 0 /* unused */
    227327static int coreAudioCFStringToCString(const CFStringRef pCFString, char **ppszString)
    228328{
     
    239339}
    240340
    241 #if 0 /* unused */
    242341static AudioDeviceID coreAudioDeviceUIDtoID(const char* pszUID)
    243342{
     
    276375*   Defined Constants And Macros                                                                                                 *
    277376*********************************************************************************************************************************/
     377
    278378/** @name Initialization status indicator used for the recreation of the AudioUnits.
    279  * @{ */
    280 #define CA_STATUS_UNINIT    UINT32_C(0) /**< The device is uninitialized */
    281 #define CA_STATUS_IN_INIT   UINT32_C(1) /**< The device is currently initializing */
    282 #define CA_STATUS_INIT      UINT32_C(2) /**< The device is initialized */
    283 #define CA_STATUS_IN_UNINIT UINT32_C(3) /**< The device is currently uninitializing */
    284 #define CA_STATUS_REINIT    UINT32_C(4) /**< The device has to be reinitialized */
    285 /** @} */
    286 
    287 
    288 /*********************************************************************************************************************************
    289 *   Global Variables                                                                                                             *
    290 *********************************************************************************************************************************/
    291 /* Error code which indicates "End of data" */
    292 static const OSStatus g_caConverterEOFDErr = 0x656F6664; /* 'eofd' */
    293 
    294 
    295 /*********************************************************************************************************************************
    296 *   Structures and Typedefs                                                                                                      *
    297 *********************************************************************************************************************************/
     379 *
     380 * Global structures section
     381 *
     382 ******************************************************************************/
     383
     384/**
     385 * Enumeration for a Core Audio stream status.
     386 */
     387typedef enum COREAUDIOSTATUS
     388{
     389    /** The device is uninitialized. */
     390    COREAUDIOSTATUS_UNINIT  = 0,
     391    /** The device is currently initializing. */
     392    COREAUDIOSTATUS_IN_INIT,
     393    /** The device is initialized. */
     394    COREAUDIOSTATUS_INIT,
     395    /** The device is currently uninitializing. */
     396    COREAUDIOSTATUS_IN_UNINIT,
     397    /* The device has to be reinitialized */
     398    COREAUDIOSTATUS_REINIT,
     399    /** The usual 32-bit hack. */
     400    COREAUDIOSTATUS_32BIT_HACK = 0x7fffffff
     401} COREAUDIOSTATUS, *PCOREAUDIOSTATUS;
     402
     403#ifdef VBOX_WITH_AUDIO_CA_CONVERTER
     404 /* Error code which indicates "End of data" */
     405 static const OSStatus caConverterEOFDErr = 0x656F6664; /* 'eofd' */
     406#endif
     407
    298408/* Prototypes needed for COREAUDIOSTREAMCBCTX. */
    299 struct COREAUDIOSTREAMIN;
    300 typedef struct COREAUDIOSTREAMIN *PCOREAUDIOSTREAMIN;
    301 struct COREAUDIOSTREAMOUT;
    302 typedef struct COREAUDIOSTREAMOUT *PCOREAUDIOSTREAMOUT;
    303 
    304 /**
    305  * Host Coreaudio driver instance data.
    306  * @implements PDMIAUDIOCONNECTOR
    307  */
    308 typedef struct DRVHOSTCOREAUDIO
    309 {
    310     /** Pointer to the driver instance structure. */
    311     PPDMDRVINS    pDrvIns;
    312     /** Pointer to host audio interface. */
    313     PDMIHOSTAUDIO IHostAudio;
    314 } DRVHOSTCOREAUDIO, *PDRVHOSTCOREAUDIO;
    315 
    316 /** Converts a pointer to DRVHOSTCOREAUDIO::IHostAudio to a PDRVHOSTCOREAUDIO. */
    317 #define PDMIHOSTAUDIO_2_DRVHOSTCOREAUDIO(pInterface) RT_FROM_MEMBER(pInterface, DRVHOSTCOREAUDIO, IHostAudio)
    318 
    319 /**
    320  * Simple structure for maintaining a stream's callback context.
    321  ** @todo Remove this as soon as we have unified input/output streams in this backend.
    322  */
    323 typedef struct COREAUDIOSTREAMCBCTX
    324 {
    325     /** Pointer to driver instance. */
    326     PDRVHOSTCOREAUDIO       pThis;
     409struct COREAUDIOSTREAM;
     410typedef struct COREAUDIOSTREAM *PCOREAUDIOSTREAM;
     411
     412/**
     413 * Structure for keeping a conversion callback context.
     414 * This is needed when using an audio converter during input/output processing.
     415 */
     416typedef struct COREAUDIOCONVCBCTX
     417{
     418    /** Pointer to the stream this context is bound to. */
     419    PCOREAUDIOSTREAM             pStream;
     420    /** Source stream description. */
     421    AudioStreamBasicDescription  asbdSrc;
     422    /** Destination stream description. */
     423    AudioStreamBasicDescription  asbdDst;
     424    /** Pointer to native buffer list used for rendering the source audio data into. */
     425    AudioBufferList             *pBufLstSrc;
     426    /** Total packet conversion count. */
     427    UInt32                       uPacketCnt;
     428    /** Current packet conversion index. */
     429    UInt32                       uPacketIdx;
     430    /** Error count, for limiting the logging. */
     431    UInt32                       cErrors;
     432} COREAUDIOCONVCBCTX, *PCOREAUDIOCONVCBCTX;
     433
     434/**
     435 * Structure for keeping the input stream specifics.
     436 */
     437typedef struct COREAUDIOSTREAMIN
     438{
     439#ifdef VBOX_WITH_AUDIO_CA_CONVERTER
     440    /** The audio converter if necessary. NULL if no converter is being used. */
     441    AudioConverterRef           ConverterRef;
     442    /** Callback context for the audio converter. */
     443    COREAUDIOCONVCBCTX          convCbCtx;
     444#endif
     445    /** The ratio between the device & the stream sample rate. */
     446    Float64                     sampleRatio;
     447} COREAUDIOSTREAMIN, *PCOREAUDIOSTREAMIN;
     448
     449/**
     450 * Structure for keeping the output stream specifics.
     451 */
     452typedef struct COREAUDIOSTREAMOUT
     453{
     454    /** Nothing here yet. */
     455} COREAUDIOSTREAMOUT, *PCOREAUDIOSTREAMOUT;
     456
     457/**
     458 * Structure for maintaining a Core Audio stream.
     459 */
     460typedef struct COREAUDIOSTREAM
     461{
     462    /** Host input stream.
     463     *  Note: Always must come first in this structure! */
     464    PDMAUDIOSTREAM          Stream;
     465    /** Note: This *always* must come first! */
     466    union
     467    {
     468        COREAUDIOSTREAMIN   In;
     469        COREAUDIOSTREAMOUT  Out;
     470    };
     471    /** List node for the device's stream list. */
     472    RTLISTNODE              Node;
     473    /** Pointer to driver instance this stream is bound to. */
     474    PDRVHOSTCOREAUDIO       pDrv;
    327475    /** The stream's direction. */
    328476    PDMAUDIODIR             enmDir;
    329     union
    330     {
    331         /** Pointer to self, if it's an input stream. */
    332         PCOREAUDIOSTREAMIN  pIn;
    333         /** Pointer to self, if it's an output stream. */
    334         PCOREAUDIOSTREAMOUT pOut;
    335     };
    336 } COREAUDIOSTREAMCBCTX, *PCOREAUDIOSTREAMCBCTX;
    337 
    338 /**
    339  * Structure for keeping a conversion callback context.
    340  * This is needed when using an audio converter during input/output processing.
    341  */
    342 typedef struct COREAUDIOCONVCBCTX
    343 {
    344     /** Pointer to stream context this converter callback context
    345      *  is bound to. */
    346     /** @todo Remove this as soon as we have unified input/output streams in this backend. */
    347     COREAUDIOSTREAMCBCTX        pStream;
    348     /** Source stream description. */
    349     AudioStreamBasicDescription asbdSrc;
    350     /** Destination stream description. */
    351     AudioStreamBasicDescription asbdDst;
    352     /** Native buffer list used for rendering the source audio data into. */
    353     AudioBufferList             bufLstSrc;
    354     /** Total packet conversion count. */
    355     UInt32                      uPacketCnt;
    356     /** Current packet conversion index. */
    357     UInt32                      uPacketIdx;
    358 } COREAUDIOCONVCBCTX, *PCOREAUDIOCONVCBCTX;
    359 
    360 /** @todo Unify COREAUDIOSTREAMOUT / COREAUDIOSTREAMIN. */
    361 typedef struct COREAUDIOSTREAMOUT
    362 {
    363     /** Host output stream.
    364      *  Note: Always must come first in this structure! */
    365     PDMAUDIOSTREAM              Stream;
    366     /** Stream description which is default on the device. */
    367     AudioStreamBasicDescription deviceFormat;
    368     /** Stream description which is selected for using with VBox. */
    369     AudioStreamBasicDescription streamFormat;
    370     /** The audio device ID of the currently used device. */
    371     AudioDeviceID               deviceID;
    372     /** The AudioUnit being used. */
    373     AudioUnit                   audioUnit;
    374     /** A ring buffer for transferring data to the playback thread. */
    375     PRTCIRCBUF                  pCircBuf;
     477    /** The audio unit for this stream. */
     478    COREAUDIOUNIT           Unit;
    376479    /** Initialization status tracker. Used when some of the device parameters
    377480     *  or the device itself is changed during the runtime. */
    378     volatile uint32_t           status;
    379     /** Flag whether the "default device changed" listener was registered. */
    380     bool                        fDefDevChgListReg;
    381     /** Flag whether the "device state changed" listener was registered. */
    382     bool                        fDevStateChgListReg;
    383     /** Callback context for this stream for handing this stream in to
    384      *  a CoreAudio callback.
    385      ** @todo Remove this as soon as we have unified input/output streams in this backend. */
    386     COREAUDIOSTREAMCBCTX        cbCtx;
    387 } COREAUDIOSTREAMOUT, *PCOREAUDIOSTREAMOUT;
    388 
    389 typedef struct COREAUDIOSTREAMIN
    390 {
    391     /** Host input stream.
    392      *  Note: Always must come first in this structure! */
    393     PDMAUDIOSTREAM              Stream;
    394     /** Stream description which is default on the device. */
    395     AudioStreamBasicDescription deviceFormat;
    396     /** Stream description which is selected for using with VBox. */
    397     AudioStreamBasicDescription streamFormat;
    398     /** The audio device ID of the currently used device. */
    399     AudioDeviceID               deviceID;
    400     /** The AudioUnit used. */
    401     AudioUnit                   audioUnit;
    402     /** A ring buffer for transferring data from the capturing thread. */
    403     PRTCIRCBUF                  pCircBuf;
    404     /** The audio converter if necessary. NULL if no converter is being used. */
    405     AudioConverterRef           pConverter;
    406     /** Callback context for the audio converter. */
    407     COREAUDIOCONVCBCTX          convCbCtx;
    408     /** The ratio between the device & the stream sample rate. */
    409     Float64                     sampleRatio;
    410     /** Initialization status tracker. Used when some of the device parameters
    411      *  or the device itself is changed during the runtime. */
    412     volatile uint32_t           status;
    413     /** Flag whether the "default device changed" listener was registered. */
    414     bool                        fDefDevChgListReg;
    415     /** Flag whether the "device state changed" listener was registered. */
    416     bool                        fDevStateChgListReg;
    417     /** Callback context for this stream for handing this stream in to
    418      *  a CoreAudio callback.
    419      ** @todo Remove this as soon as we have unified input/output streams in this backend. */
    420     COREAUDIOSTREAMCBCTX        cbCtx;
    421 } COREAUDIOSTREAMIN, *PCOREAUDIOSTREAMIN;
    422 
    423 
    424 /*********************************************************************************************************************************
    425 *   Internal Functions                                                                                                           *
    426 *********************************************************************************************************************************/
    427 static OSStatus coreAudioPlaybackAudioDevicePropertyChanged(AudioObjectID propertyID, UInt32 cAddresses, const AudioObjectPropertyAddress properties[], void *pvUser);
     481    volatile uint32_t       status;
     482    /** An internal ring buffer for transferring data from/to the rendering callbacks. */
     483    PRTCIRCBUF              pCircBuf;
     484} COREAUDIOSTREAM, *PCOREAUDIOSTREAM;
     485
     486static int coreAudioStreamInit(PCOREAUDIOSTREAM pCAStream, PDRVHOSTCOREAUDIO pThis, PPDMAUDIODEVICE pDev);
     487static int coreAudioStreamReinit(PDRVHOSTCOREAUDIO pThis, PCOREAUDIOSTREAM pCAStream, PPDMAUDIODEVICE pDev);
     488static int coreAudioStreamUninit(PCOREAUDIOSTREAM pCAStream);
     489
     490static int coreAudioStreamInitIn(PCOREAUDIOSTREAM pCAStream, PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq);
     491static int coreAudioStreamInitOut(PCOREAUDIOSTREAM pCAStream, PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq);
     492
     493static int coreAudioStreamControl(PDRVHOSTCOREAUDIO pThis, PCOREAUDIOSTREAM pCAStream, PDMAUDIOSTREAMCMD enmStreamCmd);
     494
     495static int coreAudioDeviceRegisterCallbacks(PDRVHOSTCOREAUDIO pThis, PPDMAUDIODEVICE pDev);
     496static int coreAudioDeviceUnregisterCallbacks(PDRVHOSTCOREAUDIO pThis, PPDMAUDIODEVICE pDev);
     497static void coreAudioDeviceDataInit(PCOREAUDIODEVICEDATA pDevData, AudioDeviceID deviceID, PDRVHOSTCOREAUDIO pDrv);
     498
     499static OSStatus coreAudioDevPropChgCb(AudioObjectID propertyID, UInt32 nAddresses, const AudioObjectPropertyAddress properties[], void *pvUser);
    428500static OSStatus coreAudioPlaybackCb(void *pvUser, AudioUnitRenderActionFlags *pActionFlags, const AudioTimeStamp *pAudioTS, UInt32 uBusID, UInt32 cFrames, AudioBufferList* pBufData);
    429501
    430502
     503/**
     504 * Returns whether an assigned audio unit to a given stream is running or not.
     505 *
     506 * @return  True if audio unit is running, false if not.
     507 * @param   pStream             Audio stream to check.
     508 */
     509static bool coreAudioUnitIsRunning(PCOREAUDIOSTREAM pStream)
     510{
     511    AssertPtrReturn(pStream, false);
     512
     513    UInt32 uFlag = 0;
     514    UInt32 uSize = sizeof(uFlag);
     515    OSStatus err = AudioUnitGetProperty(pStream->Unit.audioUnit, kAudioOutputUnitProperty_IsRunning, kAudioUnitScope_Global,
     516                                        0, &uFlag, &uSize);
     517    if (err != kAudioHardwareNoError)
     518        LogRel(("CoreAudio: Could not determine whether the audio unit is running (%RI32)\n", err));
     519
     520    Log3Func(("%s -> %RU32\n", pStream->enmDir == PDMAUDIODIR_IN ? "Input" : "Output", uFlag));
     521
     522    return (uFlag >= 1);
     523}
     524
     525
     526#ifdef VBOX_WITH_AUDIO_CA_CONVERTER
    431527/**
    432528 * Initializes a conversion callback context.
     
    434530 * @return  IPRT status code.
    435531 * @param   pConvCbCtx          Conversion callback context to initialize.
     532 * @param   pStream             Pointer to stream to use.
    436533 * @param   pASBDSrc            Input (source) stream description to use.
    437534 * @param   pASBDDst            Output (destination) stream description to use.
    438535 */
    439 static int coreAudioInitConvCbCtx(PCOREAUDIOCONVCBCTX pConvCbCtx,
     536static int coreAudioInitConvCbCtx(PCOREAUDIOCONVCBCTX pConvCbCtx, PCOREAUDIOSTREAM pStream,
    440537                                  AudioStreamBasicDescription *pASBDSrc, AudioStreamBasicDescription *pASBDDst)
    441538{
    442539    AssertPtrReturn(pConvCbCtx, VERR_INVALID_POINTER);
     540    AssertPtrReturn(pStream,    VERR_INVALID_POINTER);
    443541    AssertPtrReturn(pASBDSrc,   VERR_INVALID_POINTER);
    444542    AssertPtrReturn(pASBDDst,   VERR_INVALID_POINTER);
    445543
     544#ifdef DEBUG
     545    coreAudioPrintASBD("CbCtx: Src", pASBDSrc);
     546    coreAudioPrintASBD("CbCtx: Dst", pASBDDst);
     547#endif
     548
     549    pConvCbCtx->pStream = pStream;
     550
    446551    memcpy(&pConvCbCtx->asbdSrc, pASBDSrc, sizeof(AudioStreamBasicDescription));
    447552    memcpy(&pConvCbCtx->asbdDst, pASBDDst, sizeof(AudioStreamBasicDescription));
    448553
    449     /* Create the AudioBufferList structure with one buffer. */
    450     pConvCbCtx->bufLstSrc.mNumberBuffers              = 1;
    451 
    452     /* Initialize the conversion buffer. */
    453     pConvCbCtx->bufLstSrc.mBuffers[0].mNumberChannels = pConvCbCtx->asbdSrc.mChannelsPerFrame;
    454     pConvCbCtx->bufLstSrc.mBuffers[0].mDataByteSize   = 0;
    455     pConvCbCtx->bufLstSrc.mBuffers[0].mData           = NULL;
     554    pConvCbCtx->pBufLstSrc = NULL;
     555    pConvCbCtx->cErrors    = 0;
    456556
    457557    return VINF_SUCCESS;
    458558}
     559
    459560
    460561/**
     
    468569    AssertPtrReturnVoid(pConvCbCtx);
    469570
     571    pConvCbCtx->pStream = NULL;
     572
    470573    RT_ZERO(pConvCbCtx->asbdSrc);
    471574    RT_ZERO(pConvCbCtx->asbdDst);
    472575
    473     pConvCbCtx->bufLstSrc.mNumberBuffers = 0;
    474 }
    475 
    476 /**
    477  * Does a (Re-)enumeration of the host's playback + recording devices.
     576    pConvCbCtx->pBufLstSrc = NULL;
     577    pConvCbCtx->cErrors    = 0;
     578}
     579#endif /* VBOX_WITH_AUDIO_CA_CONVERTER */
     580
     581
     582/**
     583 * Does a (re-)enumeration of the host's playback + recording devices.
    478584 *
    479585 * @return  IPRT status code.
    480586 * @param   pThis               Host audio driver instance.
    481  * @param   pCfg                Where to store the enumeration results.
    482  * @param   fEnum               Enumeration flags.
    483  */
    484 static int coreAudioDevicesEnumerate(PDRVHOSTCOREAUDIO pThis, PPDMAUDIOBACKENDCFG pCfg, bool fIn, uint32_t fEnum)
    485 {
    486     RT_NOREF(fEnum);
    487     AssertPtrReturn(pThis, VERR_INVALID_POINTER);
    488     /* pCfg is optional. */
     587 * @param   enmUsage            Which devices to enumerate.
     588 * @param   pDevEnm             Where to store the enumerated devices.
     589 */
     590static int coreAudioDevicesEnumerate(PDRVHOSTCOREAUDIO pThis, PDMAUDIODIR enmUsage, PPDMAUDIODEVICEENUM pDevEnm)
     591{
     592    AssertPtrReturn(pThis,   VERR_INVALID_POINTER);
     593    AssertPtrReturn(pDevEnm, VERR_INVALID_POINTER);
    489594
    490595    int rc = VINF_SUCCESS;
    491596
    492     uint8_t cDevs = 0;
    493 
    494597    do
    495598    {
     599        AudioDeviceID defaultDeviceID = kAudioDeviceUnknown;
     600
     601        /* Fetch the default audio device currently in use. */
     602        AudioObjectPropertyAddress propAdrDefaultDev = {   enmUsage == PDMAUDIODIR_IN
     603                                                         ? kAudioHardwarePropertyDefaultInputDevice
     604                                                         : kAudioHardwarePropertyDefaultOutputDevice,
     605                                                         kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
     606        UInt32 uSize = sizeof(defaultDeviceID);
     607        OSStatus err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &propAdrDefaultDev, 0, NULL, &uSize, &defaultDeviceID);
     608        if (err != noErr)
     609        {
     610            LogRel(("CoreAudio: Unable to determine default %s device (%RI32)\n",
     611                    enmUsage == PDMAUDIODIR_IN ? "capturing" : "playback", err));
     612            return VERR_NOT_FOUND;
     613        }
     614
     615        if (defaultDeviceID == kAudioDeviceUnknown)
     616        {
     617            LogFunc(("No default %s device found\n", enmUsage == PDMAUDIODIR_IN ? "capturing" : "playback"));
     618            /* Keep going. */
     619        }
     620
    496621        AudioObjectPropertyAddress propAdrDevList = { kAudioHardwarePropertyDevices, kAudioObjectPropertyScopeGlobal,
    497622                                                      kAudioObjectPropertyElementMaster };
    498         UInt32 uSize = 0;
    499         OSStatus err = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &propAdrDevList, 0, NULL, &uSize);
     623
     624        err = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &propAdrDevList, 0, NULL, &uSize);
    500625        if (err != kAudioHardwareNoError)
    501626            break;
     
    509634            break;
    510635
    511         UInt32 cDevices = uSize / sizeof (AudioDeviceID);
    512         for (UInt32 i = 0; i < cDevices; i++)
    513         {
    514             AudioDeviceID curDevID = pDevIDs[i];
     636        rc = DrvAudioHlpDeviceEnumInit(pDevEnm);
     637        if (RT_FAILURE(rc))
     638            break;
     639
     640        UInt16 cDevices = uSize / sizeof(AudioDeviceID);
     641
     642        PPDMAUDIODEVICE pDev = NULL;
     643        for (UInt16 i = 0; i < cDevices; i++)
     644        {
     645            if (pDev) /* Some (skipped) device to clean up first? */
     646                DrvAudioHlpDeviceFree(pDev);
     647
     648            pDev = DrvAudioHlpDeviceAlloc(sizeof(COREAUDIODEVICEDATA));
     649            if (!pDev)
     650            {
     651                rc = VERR_NO_MEMORY;
     652                break;
     653            }
     654
     655            /* Set usage. */
     656            pDev->enmUsage = enmUsage;
     657
     658            /* Init backend-specific device data. */
     659            PCOREAUDIODEVICEDATA pDevData = (PCOREAUDIODEVICEDATA)pDev->pvData;
     660            AssertPtr(pDevData);
     661            coreAudioDeviceDataInit(pDevData, pDevIDs[i], pThis);
    515662
    516663            /* Check if the device is valid. */
     664            AudioDeviceID curDevID = pDevData->deviceID;
     665
    517666            AudioObjectPropertyAddress propAddrCfg = { kAudioDevicePropertyStreamConfiguration,
    518                                                        fIn ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput,
     667                                                         enmUsage == PDMAUDIODIR_IN
     668                                                       ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput,
    519669                                                       kAudioObjectPropertyElementMaster };
    520670
     
    527677                continue;
    528678
    529             bool fIsValid = false;
    530 
    531679            err = AudioObjectGetPropertyData(curDevID, &propAddrCfg, 0, NULL, &uSize, pBufList);
    532680            if (err == noErr)
     
    534682                for (UInt32 a = 0; a < pBufList->mNumberBuffers; a++)
    535683                {
    536                     fIsValid = pBufList->mBuffers[a].mNumberChannels > 0;
    537                     if (fIsValid)
    538                         break;
     684                    if (enmUsage == PDMAUDIODIR_IN)
     685                        pDev->cMaxInputChannels  += pBufList->mBuffers[a].mNumberChannels;
     686                    else if (enmUsage == PDMAUDIODIR_OUT)
     687                        pDev->cMaxOutputChannels += pBufList->mBuffers[a].mNumberChannels;
    539688                }
    540689            }
     
    546695            }
    547696
    548             if (!fIsValid)
     697            /* Check if the device is valid, e.g. has any input/output channels according to its usage. */
     698            if (   enmUsage == PDMAUDIODIR_IN
     699                && !pDev->cMaxInputChannels)
     700            {
    549701                continue;
     702            }
     703            else if (   enmUsage == PDMAUDIODIR_OUT
     704                     && !pDev->cMaxOutputChannels)
     705            {
     706                continue;
     707            }
    550708
    551709            /* Resolve the device's name. */
    552710            AudioObjectPropertyAddress propAddrName = { kAudioObjectPropertyName,
    553                                                         fIn ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput,
     711                                                          enmUsage == PDMAUDIODIR_IN
     712                                                        ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput,
    554713                                                        kAudioObjectPropertyElementMaster };
    555714            uSize = sizeof(CFStringRef);
     
    567726                    && CFStringGetCString(pcfstrName, pszName, uMax, kCFStringEncodingUTF8))
    568727                {
    569                     LogRel2(("CoreAudio: Found %s device '%s'\n", fIn ? "recording" : "playback", pszName));
    570                     cDevs++;
     728                    RTStrPrintf(pDev->szName, sizeof(pDev->szName), "%s", pszName);
    571729                }
    572730
     
    579737
    580738            CFRelease(pcfstrName);
     739
     740            /* Adjust flags. */
     741            if (curDevID == defaultDeviceID) /* Is the device the default device? */
     742                pDev->fFlags |= PDMAUDIODEV_FLAGS_DEFAULT;
     743
     744            /* Add the device to the enumeration. */
     745            rc = DrvAudioHlpDeviceEnumAdd(pDevEnm, pDev);
     746            if (RT_FAILURE(rc))
     747                break;
     748
     749            /* NULL device pointer because it's now part of the device enumeration. */
     750            pDev = NULL;
     751        }
     752
     753        if (RT_FAILURE(rc))
     754        {
     755            DrvAudioHlpDeviceFree(pDev);
     756            pDev = NULL;
    581757        }
    582758
    583759    } while (0);
    584760
    585     if (fIn)
    586         LogRel2(("CoreAudio: Found %RU8 recording device(s)\n", cDevs));
     761    if (RT_SUCCESS(rc))
     762    {
     763#ifdef DEBUG
     764        LogFunc(("Devices for pDevEnm=%p, enmUsage=%RU32:\n", pDevEnm, enmUsage));
     765        DrvAudioHlpDeviceEnumPrint("Core Audio", pDevEnm);
     766#endif
     767    }
    587768    else
    588         LogRel2(("CoreAudio: Found %RU8 playback device(s)\n", cDevs));
    589 
    590     if (pCfg)
    591     {
    592         if (fIn)
    593             pCfg->cSources = cDevs;
    594         else
    595             pCfg->cSinks   = cDevs;
    596     }
     769        DrvAudioHlpDeviceEnumFree(pDevEnm);
    597770
    598771    LogFlowFuncLeaveRC(rc);
     
    600773}
    601774
    602 /**
    603  * Updates this host driver's internal status, according to the global, overall input/output
    604  * state and all connected (native) audio streams.
     775
     776/**
     777 * Checks if an audio device with a specific device ID is in the given device
     778 * enumeration or not.
    605779 *
     780 * @retval  true if the node is the last element in the list.
     781 * @retval  false otherwise.
     782 *
     783 * @param   pEnmSrc               Device enumeration to search device ID in.
     784 * @param   deviceID              Device ID to search.
     785 */
     786bool coreAudioDevicesHasDevice(PPDMAUDIODEVICEENUM pEnmSrc, AudioDeviceID deviceID)
     787{
     788    PPDMAUDIODEVICE pDevSrc;
     789    RTListForEach(&pEnmSrc->lstDevices, pDevSrc, PDMAUDIODEVICE, Node)
     790    {
     791        PCOREAUDIODEVICEDATA pDevSrcData = (PCOREAUDIODEVICEDATA)pDevSrc->pvData;
     792        AssertPtr(pDevSrcData);
     793
     794        if (pDevSrcData->deviceID == deviceID)
     795            return true;
     796    }
     797
     798    return false;
     799}
     800
     801
     802/**
     803 * Enumerates all host devices and builds a final device enumeration list, consisting
     804 * of (duplex) input and output devices.
     805 *
     806 * @return  IPRT status code.
    606807 * @param   pThis               Host audio driver instance.
    607  * @param   pCfg                Where to store the backend configuration. Optional.
    608  * @param   fEnum               Enumeration flags.
    609  */
    610 int coreAudioUpdateStatusInternalEx(PDRVHOSTCOREAUDIO pThis, PPDMAUDIOBACKENDCFG pCfg, uint32_t fEnum)
    611 {
    612     RT_NOREF(fEnum);
    613     AssertPtrReturn(pThis, VERR_INVALID_POINTER);
    614     /* pCfg is optional. */
    615 
    616     PDMAUDIOBACKENDCFG Cfg;
    617     RT_ZERO(Cfg);
    618 
    619     Cfg.cbStreamOut    = sizeof(COREAUDIOSTREAMOUT);
    620     Cfg.cbStreamIn     = sizeof(COREAUDIOSTREAMIN);
    621     Cfg.cMaxStreamsIn  = UINT32_MAX;
    622     Cfg.cMaxStreamsOut = UINT32_MAX;
    623 
    624     int rc = coreAudioDevicesEnumerate(pThis, &Cfg, false /* fIn */, 0 /* fEnum */);
    625     AssertRC(rc);
    626     rc = coreAudioDevicesEnumerate(pThis, &Cfg, true /* fIn */, 0 /* fEnum */);
    627     AssertRC(rc);
    628 
    629     if (pCfg)
    630         memcpy(pCfg, &Cfg, sizeof(PDMAUDIOBACKENDCFG));
     808 * @param   pEnmDst             Where to store the device enumeration list.
     809 */
     810int coreAudioDevicesEnumerateAll(PDRVHOSTCOREAUDIO pThis, PPDMAUDIODEVICEENUM pEnmDst)
     811{
     812    PDMAUDIODEVICEENUM devEnmIn;
     813    int rc = coreAudioDevicesEnumerate(pThis, PDMAUDIODIR_IN, &devEnmIn);
     814    if (RT_SUCCESS(rc))
     815    {
     816        PDMAUDIODEVICEENUM devEnmOut;
     817        rc = coreAudioDevicesEnumerate(pThis, PDMAUDIODIR_OUT, &devEnmOut);
     818        if (RT_SUCCESS(rc))
     819        {
     820            /*
     821             * Build up the final device enumeration, based on the input and output device lists
     822             * just enumerated.
     823             *
     824             * Also make sure to handle duplex devices, that is, devices which act as input and output
     825             * at the same time.
     826             */
     827
     828            rc = DrvAudioHlpDeviceEnumInit(pEnmDst);
     829            if (RT_SUCCESS(rc))
     830            {
     831                PPDMAUDIODEVICE pDevSrcIn;
     832                RTListForEach(&devEnmIn.lstDevices, pDevSrcIn, PDMAUDIODEVICE, Node)
     833                {
     834                    PCOREAUDIODEVICEDATA pDevSrcInData = (PCOREAUDIODEVICEDATA)pDevSrcIn->pvData;
     835                    AssertPtr(pDevSrcInData);
     836
     837                    PPDMAUDIODEVICE pDevDst = DrvAudioHlpDeviceAlloc(sizeof(COREAUDIODEVICEDATA));
     838                    if (!pDevDst)
     839                    {
     840                        rc = VERR_NO_MEMORY;
     841                        break;
     842                    }
     843
     844                    PCOREAUDIODEVICEDATA pDevDstData = (PCOREAUDIODEVICEDATA)pDevDst->pvData;
     845                    AssertPtr(pDevDstData);
     846                    coreAudioDeviceDataInit(pDevDstData, pDevSrcInData->deviceID, pThis);
     847
     848                    RTStrCopy(pDevDst->szName, sizeof(pDevDst->szName), pDevSrcIn->szName);
     849
     850                    pDevDst->enmUsage          = PDMAUDIODIR_IN; /* Input device by default (simplex). */
     851                    pDevDst->cMaxInputChannels = pDevSrcIn->cMaxInputChannels;
     852
     853                    /* Handle flags. */
     854                    if (pDevSrcIn->fFlags & PDMAUDIODEV_FLAGS_DEFAULT)
     855                        pDevDst->fFlags |= PDMAUDIODEV_FLAGS_DEFAULT;
     856                    /** @todo Handle hot plugging? */
     857
     858                    /*
     859                     * Now search through the list of all found output devices and check if we found
     860                     * an output device with the same device ID as the currently handled input device.
     861                     *
     862                     * If found, this means we have to treat that device as a duplex device then.
     863                     */
     864                    PPDMAUDIODEVICE pDevSrcOut;
     865                    RTListForEach(&devEnmOut.lstDevices, pDevSrcOut, PDMAUDIODEVICE, Node)
     866                    {
     867                        PCOREAUDIODEVICEDATA pDevSrcOutData = (PCOREAUDIODEVICEDATA)pDevSrcOut->pvData;
     868                        AssertPtr(pDevSrcOutData);
     869
     870                        if (pDevSrcInData->deviceID == pDevSrcOutData->deviceID)
     871                        {
     872                            pDevDst->enmUsage           = PDMAUDIODIR_ANY;
     873                            pDevDst->cMaxOutputChannels = pDevSrcOut->cMaxOutputChannels;
     874                            break;
     875                        }
     876                    }
     877
     878                    if (RT_SUCCESS(rc))
     879                    {
     880                        rc = DrvAudioHlpDeviceEnumAdd(pEnmDst, pDevDst);
     881                    }
     882                    else
     883                    {
     884                        DrvAudioHlpDeviceFree(pDevDst);
     885                        pDevDst = NULL;
     886                    }
     887                }
     888
     889                if (RT_SUCCESS(rc))
     890                {
     891                    /*
     892                     * As a last step, add all remaining output devices which have not been handled in the loop above,
     893                     * that is, all output devices which operate in simplex mode.
     894                     */
     895                    PPDMAUDIODEVICE pDevSrcOut;
     896                    RTListForEach(&devEnmOut.lstDevices, pDevSrcOut, PDMAUDIODEVICE, Node)
     897                    {
     898                        PCOREAUDIODEVICEDATA pDevSrcOutData = (PCOREAUDIODEVICEDATA)pDevSrcOut->pvData;
     899                        AssertPtr(pDevSrcOutData);
     900
     901                        if (coreAudioDevicesHasDevice(pEnmDst, pDevSrcOutData->deviceID))
     902                            continue; /* Already in our list, skip. */
     903
     904                        PPDMAUDIODEVICE pDevDst = DrvAudioHlpDeviceAlloc(sizeof(COREAUDIODEVICEDATA));
     905                        if (!pDevDst)
     906                        {
     907                            rc = VERR_NO_MEMORY;
     908                            break;
     909                        }
     910
     911                        PCOREAUDIODEVICEDATA pDevDstData = (PCOREAUDIODEVICEDATA)pDevDst->pvData;
     912                        AssertPtr(pDevDstData);
     913                        coreAudioDeviceDataInit(pDevDstData, pDevSrcOutData->deviceID, pThis);
     914
     915                        RTStrCopy(pDevDst->szName, sizeof(pDevDst->szName), pDevSrcOut->szName);
     916
     917                        pDevDst->enmUsage           = PDMAUDIODIR_OUT;
     918                        pDevDst->cMaxOutputChannels = pDevSrcOut->cMaxOutputChannels;
     919
     920                        pDevDstData->deviceID       = pDevSrcOutData->deviceID;
     921
     922                        /* Handle flags. */
     923                        if (pDevSrcOut->fFlags & PDMAUDIODEV_FLAGS_DEFAULT)
     924                            pDevDst->fFlags |= PDMAUDIODEV_FLAGS_DEFAULT;
     925                        /** @todo Handle hot plugging? */
     926
     927                        rc = DrvAudioHlpDeviceEnumAdd(pEnmDst, pDevDst);
     928                        if (RT_FAILURE(rc))
     929                        {
     930                            DrvAudioHlpDeviceFree(pDevDst);
     931                            break;
     932                        }
     933                    }
     934                }
     935
     936                if (RT_FAILURE(rc))
     937                    DrvAudioHlpDeviceEnumFree(pEnmDst);
     938            }
     939
     940            DrvAudioHlpDeviceEnumFree(&devEnmOut);
     941        }
     942
     943        DrvAudioHlpDeviceEnumFree(&devEnmIn);
     944    }
     945
     946#ifdef DEBUG
     947    if (RT_SUCCESS(rc))
     948        DrvAudioHlpDeviceEnumPrint("Core Audio (Final)", pEnmDst);
     949#endif
    631950
    632951    LogFlowFuncLeaveRC(rc);
     
    635954
    636955
    637 /**
    638  * Implements the OS X callback AudioObjectPropertyListenerProc.
    639  */
    640 static OSStatus drvHostCoreAudioDeviceStateChanged(AudioObjectID propertyID,
    641                                                    UInt32 cAddresses,
    642                                                    const AudioObjectPropertyAddress paProperties[],
    643                                                    void *pvUser)
    644 {
    645     RT_NOREF(propertyID, cAddresses, paProperties)
    646     LogFlowFunc(("propertyID=%u cAddresses=%u pvUser=%p\n", propertyID, cAddresses, pvUser));
    647 
    648     PCOREAUDIOSTREAMCBCTX pCbCtx = (PCOREAUDIOSTREAMCBCTX)pvUser;
    649     AssertPtr(pCbCtx);
     956#if 0
     957static int coreAudioDeviceInit(PPDMAUDIODEVICE pDev, PDRVHOSTCOREAUDIO pDrv, PDMAUDIODIR enmUsage, AudioDeviceID deviceID)
     958{
     959    AssertPtrReturn(pDev, VERR_INVALID_POINTER);
     960
     961    PCOREAUDIODEVICEDATA pData = (PCOREAUDIODEVICEDATA)pDev->pvData;
     962    AssertPtrReturn(pData, VERR_INVALID_POINTER);
     963
     964    /* Init common parameters. */
     965    pDev->enmUsage   = enmUsage;
     966
     967    /* Init Core Audio-specifics. */
     968    pData->deviceID  = deviceID;
     969    pData->pDrv      = pDrv;
     970
     971    RTListInit(&pData->lstStreams);
     972
     973    return VINF_SUCCESS;
     974}
     975#endif
     976
     977
     978/**
     979 * Initializes a Core Audio-specific device data structure.
     980 *
     981 * @returns IPRT status code.
     982 * @param   pDevData            Device data structure to initialize.
     983 * @param   deviceID            Core Audio device ID to assign this structure to.
     984 * @param   pDrv                Driver instance to use.
     985 */
     986static void coreAudioDeviceDataInit(PCOREAUDIODEVICEDATA pDevData, AudioDeviceID deviceID, PDRVHOSTCOREAUDIO pDrv)
     987{
     988    AssertPtrReturnVoid(pDevData);
     989    AssertPtrReturnVoid(pDrv);
     990
     991    pDevData->deviceID = deviceID;
     992    pDevData->pDrv     = pDrv;
     993
     994    RTListInit(&pDevData->lstStreams);
     995}
     996
     997
     998/**
     999 * Propagates an audio device status to all its connected Core Audio streams.
     1000 *
     1001 * @return IPRT status code.
     1002 * @param  pDev                 Audio device to propagate status for.
     1003 * @param  enmSts               Status to propagate.
     1004 */
     1005static int coreAudioDevicePropagateStatus(PPDMAUDIODEVICE pDev, COREAUDIOSTATUS enmSts)
     1006{
     1007    AssertPtrReturn(pDev, VERR_INVALID_POINTER);
     1008
     1009    PCOREAUDIODEVICEDATA pDevData = (PCOREAUDIODEVICEDATA)pDev->pvData;
     1010    AssertPtrReturn(pDevData, VERR_INVALID_POINTER);
     1011
     1012    /* Sanity. */
     1013    AssertPtr(pDevData->pDrv);
     1014
     1015    LogFlowFunc(("pDev=%p, pDevData=%p, enmSts=%RU32\n", pDev, pDevData, enmSts));
     1016
     1017    PCOREAUDIOSTREAM pCAStream;
     1018    RTListForEach(&pDevData->lstStreams, pCAStream, COREAUDIOSTREAM, Node)
     1019    {
     1020        LogFlowFunc(("pCAStream=%p\n", pCAStream));
     1021
     1022        /* We move the reinitialization to the next output event.
     1023         * This make sure this thread isn't blocked and the
     1024         * reinitialization is done when necessary only. */
     1025        ASMAtomicXchgU32(&pCAStream->status, enmSts);
     1026    }
     1027
     1028    return VINF_SUCCESS;
     1029}
     1030
     1031
     1032static DECLCALLBACK(OSStatus) coreAudioDeviceStateChangedCb(AudioObjectID propertyID,
     1033                                                            UInt32 nAddresses,
     1034                                                            const AudioObjectPropertyAddress properties[],
     1035                                                            void *pvUser)
     1036{
     1037    RT_NOREF(propertyID, nAddresses, properties);
     1038
     1039    LogFlowFunc(("propertyID=%u, nAddresses=%u, pvUser=%p\n", propertyID, nAddresses, pvUser));
     1040
     1041    PPDMAUDIODEVICE pDev = (PPDMAUDIODEVICE)pvUser;
     1042    AssertPtr(pDev);
     1043
     1044    PCOREAUDIODEVICEDATA pData = (PCOREAUDIODEVICEDATA)pDev->pvData;
     1045    AssertPtrReturn(pData, VERR_INVALID_POINTER);
     1046
     1047    PDRVHOSTCOREAUDIO pThis = pData->pDrv;
     1048    AssertPtr(pThis);
     1049
     1050    int rc2 = RTCritSectEnter(&pThis->CritSect);
     1051    AssertRC(rc2);
    6501052
    6511053    UInt32 uAlive = 1;
     
    6551057                                           kAudioObjectPropertyElementMaster };
    6561058
    657     AudioDeviceID deviceID = pCbCtx->enmDir == PDMAUDIODIR_IN
    658                            ? pCbCtx->pIn->deviceID : pCbCtx->pOut->deviceID;
     1059    AudioDeviceID deviceID = pData->deviceID;
    6591060
    6601061    OSStatus err = AudioObjectGetPropertyData(deviceID, &propAdr, 0, NULL, &uSize, &uAlive);
     
    6691070    if (fIsDead)
    6701071    {
    671         switch (pCbCtx->enmDir)
    672         {
    673             case PDMAUDIODIR_IN:
    674             {
    675                 PCOREAUDIOSTREAMIN pStreamIn = pCbCtx->pIn;
    676 
    677                 /* We move the reinitialization to the next output event.
    678                  * This make sure this thread isn't blocked and the
    679                  * reinitialization is done when necessary only. */
    680                 ASMAtomicXchgU32(&pStreamIn->status, CA_STATUS_REINIT);
    681 
    682                 LogRel(("CoreAudio: Recording device stopped functioning\n"));
     1072        LogRel2(("CoreAudio: Device '%s' stopped functioning\n", pDev->szName));
     1073
     1074        /* Mark device as dead. */
     1075        rc2 = coreAudioDevicePropagateStatus(pDev, COREAUDIOSTATUS_UNINIT);
     1076        AssertRC(rc2);
     1077    }
     1078
     1079    rc2 = RTCritSectLeave(&pThis->CritSect);
     1080    AssertRC(rc2);
     1081
     1082    return noErr;
     1083}
     1084
     1085/* Callback for getting notified when the default recording/playback device has been changed. */
     1086static DECLCALLBACK(OSStatus) coreAudioDefaultDeviceChangedCb(AudioObjectID propertyID,
     1087                                                              UInt32 nAddresses,
     1088                                                              const AudioObjectPropertyAddress properties[],
     1089                                                              void *pvUser)
     1090{
     1091    RT_NOREF(propertyID, nAddresses);
     1092
     1093    LogFlowFunc(("propertyID=%u, nAddresses=%u, pvUser=%p\n", propertyID, nAddresses, pvUser));
     1094
     1095    PDRVHOSTCOREAUDIO pThis = (PDRVHOSTCOREAUDIO)pvUser;
     1096    AssertPtr(pThis);
     1097
     1098    int rc2 = RTCritSectEnter(&pThis->CritSect);
     1099    AssertRC(rc2);
     1100
     1101    OSStatus err = noErr;
     1102
     1103    for (UInt32 idxAddress = 0; idxAddress < nAddresses; idxAddress++)
     1104    {
     1105        PPDMAUDIODEVICE pDev = NULL;
     1106
     1107        /*
     1108         * Check if the default input / output device has been changed.
     1109         */
     1110        const AudioObjectPropertyAddress *pProperty = &properties[idxAddress];
     1111        switch (pProperty->mSelector)
     1112        {
     1113            case kAudioHardwarePropertyDefaultInputDevice:
     1114                LogFlowFunc(("kAudioHardwarePropertyDefaultInputDevice\n"));
     1115                pDev = pThis->pDefaultDevIn;
    6831116                break;
    684             }
    685 
    686             case PDMAUDIODIR_OUT:
    687             {
    688                 PCOREAUDIOSTREAMOUT pStreamOut = pCbCtx->pOut;
    689 
    690                 /* We move the reinitialization to the next output event.
    691                  * This make sure this thread isn't blocked and the
    692                  * reinitialization is done when necessary only. */
    693                 ASMAtomicXchgU32(&pStreamOut->status, CA_STATUS_REINIT);
    694 
    695                 LogRel(("CoreAudio: Playback device stopped functioning\n"));
     1117
     1118            case kAudioHardwarePropertyDefaultOutputDevice:
     1119                LogFlowFunc(("kAudioHardwarePropertyDefaultOutputDevice\n"));
     1120                pDev = pThis->pDefaultDevOut;
    6961121                break;
    697             }
    6981122
    6991123            default:
    700                 AssertMsgFailed(("Not implemented\n"));
     1124                /* Skip others. */
    7011125                break;
    7021126        }
    703     }
    704 
    705     int rc2 = coreAudioDevicesEnumerate(pCbCtx->pThis, NULL /* pCfg */, false /* fIn */, 0 /* fEnum */);
     1127
     1128        LogFlowFunc(("pDev=%p\n", pDev));
     1129
     1130        if (pDev)
     1131        {
     1132            PCOREAUDIODEVICEDATA pData = (PCOREAUDIODEVICEDATA)pDev->pvData;
     1133            AssertPtr(pData);
     1134
     1135            /* This listener is called on every change of the hardware
     1136             * device. So check if the default device has really changed. */
     1137            UInt32 uSize = sizeof(AudioDeviceID);
     1138            UInt32 uResp = 0;
     1139
     1140            err = AudioObjectGetPropertyData(kAudioObjectSystemObject, pProperty, 0, NULL, &uSize, &uResp);
     1141            if (err == noErr)
     1142            {
     1143                if (pData->deviceID != uResp) /* Has the device ID changed? */
     1144                {
     1145                    rc2 = coreAudioDevicePropagateStatus(pDev, COREAUDIOSTATUS_REINIT);
     1146                    AssertRC(rc2);
     1147                }
     1148            }
     1149        }
     1150    }
     1151
     1152#ifdef VBOX_WITH_AUDIO_CALLBACKS
     1153    if (pThis->pfnCallback)
     1154        /* Ignore rc */ pThis->pfnCallback(pThis->pDrvIns, PDMAUDIOCBTYPE_DEVICES_CHANGED, NULL, 0);
     1155#endif
     1156
     1157    rc2 = RTCritSectLeave(&pThis->CritSect);
    7061158    AssertRC(rc2);
    707     rc2 = coreAudioDevicesEnumerate(pCbCtx->pThis, NULL /* pCfg */, true /* fIn */, 0 /* fEnum */);
    708     AssertRC(rc2);
    7091159
    7101160    return noErr;
    7111161}
    7121162
    713 
    714 /**
    715  * Implements the OS X callback AudioObjectPropertyListenerProc for getting
    716  * notified when the default recording/playback device has been changed.
    717  */
    718 static OSStatus coreAudioDefaultDeviceChanged(AudioObjectID propertyID,
    719                                               UInt32 cAddresses,
    720                                               const AudioObjectPropertyAddress properties[],
    721                                               void *pvUser)
    722 {
    723     RT_NOREF(propertyID);
    724     LogFlowFunc(("propertyID=%u cAddresses=%u pvUser=%p\n", propertyID, cAddresses, pvUser));
    725 
    726     PCOREAUDIOSTREAMCBCTX pCbCtx = (PCOREAUDIOSTREAMCBCTX)pvUser;
    727     AssertPtr(pCbCtx);
    728 
    729     OSStatus err = noErr;
    730     for (UInt32 idxAddress = 0; idxAddress < cAddresses; idxAddress++)
    731     {
    732         const AudioObjectPropertyAddress *pProperty = &properties[idxAddress];
    733 
    734         switch (pProperty->mSelector)
    735         {
    736             case kAudioHardwarePropertyDefaultInputDevice:
    737             {
    738                 PCOREAUDIOSTREAMIN pStreamIn = pCbCtx->pIn;
    739                 AssertPtr(pStreamIn);
    740 
    741                 /* This listener is called on every change of the hardware
    742                  * device. So check if the default device has really changed. */
    743                 UInt32 uSize = sizeof(pStreamIn->deviceID);
    744                 UInt32 uResp;
    745                 err = AudioObjectGetPropertyData(kAudioObjectSystemObject, pProperty, 0, NULL, &uSize, &uResp);
    746 
    747                 if (err == noErr)
    748                 {
    749                     if (pStreamIn->deviceID != uResp)
    750                     {
    751                         LogRel(("CoreAudio: Default device for recording has changed\n"));
    752 
    753                         /* We move the reinitialization to the next input event.
    754                          * This make sure this thread isn't blocked and the
    755                          * reinitialization is done when necessary only. */
    756                         ASMAtomicXchgU32(&pStreamIn->status, CA_STATUS_REINIT);
    757                     }
    758                 }
    759                 break;
    760             }
    761 
    762             case kAudioHardwarePropertyDefaultOutputDevice:
    763             {
    764                 PCOREAUDIOSTREAMOUT pStreamOut = pCbCtx->pOut;
    765                 AssertPtr(pStreamOut);
    766 
    767                 /* This listener is called on every change of the hardware
    768                  * device. So check if the default device has really changed. */
    769                 AudioObjectPropertyAddress propAdr = { kAudioHardwarePropertyDefaultOutputDevice,
    770                                                        kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
    771 
    772                 UInt32 uSize = sizeof(pStreamOut->deviceID);
    773                 UInt32 uResp;
    774                 err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &propAdr, 0, NULL, &uSize, &uResp);
    775 
    776                 if (err == noErr)
    777                 {
    778                     if (pStreamOut->deviceID != uResp)
    779                     {
    780                         LogRel(("CoreAudio: Default device for playback has changed\n"));
    781 
    782                         /* We move the reinitialization to the next input event.
    783                          * This make sure this thread isn't blocked and the
    784                          * reinitialization is done when necessary only. */
    785                         ASMAtomicXchgU32(&pStreamOut->status, CA_STATUS_REINIT);
    786                     }
    787                 }
    788                 break;
    789             }
    790 
    791             default:
    792                 break;
    793         }
    794     }
    795 
    796     int rc2 = coreAudioDevicesEnumerate(pCbCtx->pThis, NULL /* pCfg */, false /* fIn */, 0 /* fEnum */);
    797     AssertRC(rc2);
    798     rc2 = coreAudioDevicesEnumerate(pCbCtx->pThis, NULL /* pCfg */, true /* fIn */, 0 /* fEnum */);
    799     AssertRC(rc2);
    800 
    801     /** @todo Implement callback notification here to let the audio connector / device emulation
    802      *        know that something has changed. */
    803 
    804     return noErr;
    805 }
    806 
    807 
    808 /**
    809  * Implements the OS X callback AudioObjectPropertyListenerProc for getting
    810  * notified when some of the properties of an audio device has changed.
    811  */
    812 static OSStatus coreAudioRecordingAudioDevicePropertyChanged(AudioObjectID                     propertyID,
    813                                                              UInt32                            cAddresses,
    814                                                              const AudioObjectPropertyAddress  paProperties[],
    815                                                              void                             *pvUser)
    816 {
    817     RT_NOREF(cAddresses, paProperties);
    818     PCOREAUDIOSTREAMIN pStreamIn = (PCOREAUDIOSTREAMIN)pvUser;
    819 
    820     switch (propertyID)
    821     {
    822 #ifdef DEBUG
    823         case kAudioDeviceProcessorOverload:
    824         {
    825             LogFunc(("Processor overload detected!\n"));
    826             break;
    827         }
    828 #endif /* DEBUG */
    829         case kAudioDevicePropertyNominalSampleRate:
    830         {
    831             LogRel(("CoreAudio: Recording sample rate changed\n"));
    832 
    833             /* We move the reinitialization to the next input event.
    834              * This make sure this thread isn't blocked and the
    835              * reinitialization is done when necessary only. */
    836             ASMAtomicXchgU32(&pStreamIn->status, CA_STATUS_REINIT);
    837             break;
    838         }
    839 
    840         default:
    841             break;
    842     }
    843 
    844     return noErr;
    845 }
    846 
    847 /**
    848  * Implements the OS X callback AudioConverterComplexInputDataProc for
    849  * converting audio input data from one format to another.
    850  */
    851 static OSStatus coreAudioConverterCallback(AudioConverterRef              inAudioConverter,
    852                                            UInt32                        *ioNumberDataPackets,
    853                                            AudioBufferList               *ioData,
    854                                            AudioStreamPacketDescription **ppASPD,
    855                                            void                          *pvUser)
    856 {
    857     RT_NOREF(inAudioConverter, ppASPD);
    858     AssertPtrReturn(ioNumberDataPackets, g_caConverterEOFDErr);
    859     AssertPtrReturn(ioData,              g_caConverterEOFDErr);
     1163/**
     1164 * Re-initializes a Core Audio stream with a specific audio device and stream configuration.
     1165 *
     1166 * @return IPRT status code.
     1167 * @param  pThis                Driver instance.
     1168 * @param  pCAStream            Audio stream to re-initialize.
     1169 * @param  pDev                 Audio device to use for re-initialization.
     1170 * @param  pCfg                 Stream configuration to use for re-initialization.
     1171 */
     1172static int coreAudioStreamReinitEx(PDRVHOSTCOREAUDIO pThis,
     1173                                   PCOREAUDIOSTREAM pCAStream, PPDMAUDIODEVICE pDev, PPDMAUDIOSTREAMCFG pCfg)
     1174{
     1175    int rc = coreAudioStreamUninit(pCAStream);
     1176    if (RT_SUCCESS(rc))
     1177    {
     1178        rc = coreAudioStreamInit(pCAStream, pThis, pDev);
     1179        if (RT_SUCCESS(rc))
     1180        {
     1181            if (pCAStream->enmDir == PDMAUDIODIR_IN)
     1182                rc = coreAudioStreamInitIn (pCAStream, pCfg /* pCfgReq */, NULL /* pCfgAcq */);
     1183            else
     1184                rc = coreAudioStreamInitOut(pCAStream, pCfg /* pCfgReq */, NULL /* pCfgAcq */);
     1185
     1186            if (RT_SUCCESS(rc))
     1187                rc = coreAudioStreamControl(pCAStream->pDrv, pCAStream, PDMAUDIOSTREAMCMD_ENABLE);
     1188
     1189            if (RT_FAILURE(rc))
     1190            {
     1191                int rc2 = coreAudioStreamUninit(pCAStream);
     1192                AssertRC(rc2);
     1193            }
     1194        }
     1195    }
     1196
     1197    if (RT_FAILURE(rc))
     1198        LogRel(("CoreAudio: Unable to re-init stream: %Rrc\n", rc));
     1199
     1200    return rc;
     1201}
     1202
     1203/**
     1204 * Re-initializes a Core Audio stream with a specific audio device.
     1205 *
     1206 * @return IPRT status code.
     1207 * @param  pThis                Driver instance.
     1208 * @param  pCAStream            Audio stream to re-initialize.
     1209 * @param  pDev                 Audio device to use for re-initialization.
     1210 */
     1211static int coreAudioStreamReinit(PDRVHOSTCOREAUDIO pThis, PCOREAUDIOSTREAM pCAStream, PPDMAUDIODEVICE pDev)
     1212{
     1213    int rc = coreAudioStreamUninit(pCAStream);
     1214    if (RT_SUCCESS(rc))
     1215    {
     1216        /* Use the acquired stream configuration from the former initialization to
     1217         * re-initialize the stream. */
     1218        PDMAUDIOSTREAMCFG CfgAcq;
     1219        rc = coreAudioASBDToStreamCfg(&pCAStream->Unit.streamFmt, &CfgAcq);
     1220        if (RT_SUCCESS(rc))
     1221            rc = coreAudioStreamReinitEx(pThis, pCAStream, pDev, &CfgAcq);
     1222    }
     1223
     1224    return rc;
     1225}
     1226
     1227#ifdef VBOX_WITH_AUDIO_CA_CONVERTER
     1228/* Callback to convert audio input data from one format to another. */
     1229static DECLCALLBACK(OSStatus) coreAudioConverterCb(AudioConverterRef              inAudioConverter,
     1230                                                   UInt32                        *ioNumberDataPackets,
     1231                                                   AudioBufferList               *ioData,
     1232                                                   AudioStreamPacketDescription **ppASPD,
     1233                                                   void                          *pvUser)
     1234{
     1235    RT_NOREF(inAudioConverter);
     1236
     1237    AssertPtrReturn(ioNumberDataPackets, caConverterEOFDErr);
     1238    AssertPtrReturn(ioData,              caConverterEOFDErr);
    8601239
    8611240    PCOREAUDIOCONVCBCTX pConvCbCtx = (PCOREAUDIOCONVCBCTX)pvUser;
     
    8671246    ioData->mBuffers[0].mData           = NULL;
    8681247
    869     /** @todo Check converter ID? */
    870 
    871     /** @todo Handled non-interleaved data by going through the full buffer list,
    872      *        not only through the first buffer like we do now. */
    873 
    874     Log3Func(("ioNumberDataPackets=%RU32\n", *ioNumberDataPackets));
    875 
    876     if (pConvCbCtx->uPacketIdx + *ioNumberDataPackets > pConvCbCtx->uPacketCnt)
    877     {
    878         Log3Func(("Limiting ioNumberDataPackets to %RU32\n", pConvCbCtx->uPacketCnt - pConvCbCtx->uPacketIdx));
    879         *ioNumberDataPackets = pConvCbCtx->uPacketCnt - pConvCbCtx->uPacketIdx;
    880     }
    881 
    882     if (*ioNumberDataPackets)
    883     {
    884         Assert(pConvCbCtx->bufLstSrc.mNumberBuffers == 1); /* Only one buffer for the source supported atm. */
    885 
    886         size_t cbOff   = pConvCbCtx->uPacketIdx * pConvCbCtx->asbdSrc.mBytesPerPacket;
    887 
    888         size_t cbAvail = RT_MIN(*ioNumberDataPackets * pConvCbCtx->asbdSrc.mBytesPerPacket,
    889                                 pConvCbCtx->bufLstSrc.mBuffers[0].mDataByteSize - cbOff);
    890 
    891         void  *pvAvail = (uint8_t *)pConvCbCtx->bufLstSrc.mBuffers[0].mData + cbOff;
    892 
    893         Log3Func(("cbOff=%zu, cbAvail=%zu\n", cbOff, cbAvail));
    894 
    895         /* Set input data for the converter to use.
    896          * Note: For VBR (Variable Bit Rates) or interleaved data handling we need multiple buffers here. */
    897         ioData->mNumberBuffers = 1;
    898 
    899         ioData->mBuffers[0].mNumberChannels = pConvCbCtx->bufLstSrc.mBuffers[0].mNumberChannels;
    900         ioData->mBuffers[0].mDataByteSize   = cbAvail;
    901         ioData->mBuffers[0].mData           = pvAvail;
     1248    if (ppASPD)
     1249    {
     1250        Log3Func(("Handling packet description not implemented\n"));
     1251    }
     1252    else
     1253    {
     1254        /** @todo Check converter ID? */
     1255
     1256        /** @todo Handled non-interleaved data by going through the full buffer list,
     1257         *        not only through the first buffer like we do now. */
     1258        Log3Func(("ioNumberDataPackets=%RU32\n", *ioNumberDataPackets));
     1259
     1260        UInt32 cNumberDataPackets = *ioNumberDataPackets;
     1261        Assert(pConvCbCtx->uPacketIdx + cNumberDataPackets <= pConvCbCtx->uPacketCnt);
     1262
     1263        if (cNumberDataPackets)
     1264        {
     1265            AssertPtr(pConvCbCtx->pBufLstSrc);
     1266            Assert(pConvCbCtx->pBufLstSrc->mNumberBuffers == 1); /* Only one buffer for the source supported atm. */
     1267
     1268            AudioStreamBasicDescription *pSrcASBD = &pConvCbCtx->asbdSrc;
     1269            AudioBuffer                 *pSrcBuf  = &pConvCbCtx->pBufLstSrc->mBuffers[0];
     1270
     1271            size_t cbOff   = pConvCbCtx->uPacketIdx * pSrcASBD->mBytesPerPacket;
     1272
     1273            cNumberDataPackets = RT_MIN((pSrcBuf->mDataByteSize - cbOff) / pSrcASBD->mBytesPerPacket,
     1274                                        cNumberDataPackets);
     1275
     1276            void  *pvAvail = (uint8_t *)pSrcBuf->mData + cbOff;
     1277            size_t cbAvail = RT_MIN(pSrcBuf->mDataByteSize - cbOff, cNumberDataPackets * pSrcASBD->mBytesPerPacket);
     1278
     1279            Log3Func(("cNumberDataPackets=%RU32, cbOff=%zu, cbAvail=%zu\n", cNumberDataPackets, cbOff, cbAvail));
     1280
     1281            /* Set input data for the converter to use.
     1282             * Note: For VBR (Variable Bit Rates) or interleaved data handling we need multiple buffers here. */
     1283            ioData->mNumberBuffers = 1;
     1284
     1285            ioData->mBuffers[0].mNumberChannels = pSrcBuf->mNumberChannels;
     1286            ioData->mBuffers[0].mDataByteSize   = cbAvail;
     1287            ioData->mBuffers[0].mData           = pvAvail;
    9021288
    9031289#ifdef DEBUG_DUMP_PCM_DATA
    904         RTFILE fh;
    905         int rc = RTFileOpen(&fh, DEBUG_DUMP_PCM_DATA_PATH "ca-converter-cb-input.pcm",
    906                             RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
    907         if (RT_SUCCESS(rc))
    908         {
    909             RTFileWrite(fh, pvAvail, cbAvail, NULL);
    910             RTFileClose(fh);
    911         }
    912         else
    913             AssertFailed();
     1290            RTFILE fh;
     1291            int rc = RTFileOpen(&fh, DEBUG_DUMP_PCM_DATA_PATH "ca-converter-cb-input.pcm",
     1292                                RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
     1293            if (RT_SUCCESS(rc))
     1294            {
     1295                RTFileWrite(fh, pvAvail, cbAvail, NULL);
     1296                RTFileClose(fh);
     1297            }
     1298            else
     1299                AssertFailed();
    9141300#endif
    915 
    916         pConvCbCtx->uPacketIdx += *ioNumberDataPackets;
    917         Assert(pConvCbCtx->uPacketIdx <= pConvCbCtx->uPacketCnt);
     1301            pConvCbCtx->uPacketIdx += cNumberDataPackets;
     1302            Assert(pConvCbCtx->uPacketIdx <= pConvCbCtx->uPacketCnt);
     1303
     1304            *ioNumberDataPackets = cNumberDataPackets;
     1305        }
    9181306    }
    9191307
     
    9231311    return noErr;
    9241312}
    925 
    926 /**
    927  * Implements the OS X callback AURenderCallback in order to feed the audio
    928  * input buffer.
    929  */
    930 static OSStatus coreAudioRecordingCb(void                       *pvUser,
    931                                      AudioUnitRenderActionFlags *pActionFlags,
    932                                      const AudioTimeStamp       *pAudioTS,
    933                                      UInt32                      uBusID,
    934                                      UInt32                      cFrames,
    935                                      AudioBufferList            *pBufData)
    936 {
    937     RT_NOREF(pBufData);
     1313#endif /* VBOX_WITH_AUDIO_CA_CONVERTER */
     1314
     1315/* Callback to feed audio input buffer. */
     1316static DECLCALLBACK(OSStatus) coreAudioCaptureCb(void                       *pvUser,
     1317                                                 AudioUnitRenderActionFlags *pActionFlags,
     1318                                                 const AudioTimeStamp       *pAudioTS,
     1319                                                 UInt32                      uBusID,
     1320                                                 UInt32                      cFrames,
     1321                                                 AudioBufferList            *pBufData)
     1322{
     1323    RT_NOREF(uBusID, pBufData);
    9381324
    9391325    /* If nothing is pending return immediately. */
     
    9411327        return noErr;
    9421328
    943     PCOREAUDIOSTREAMIN pStreamIn = (PCOREAUDIOSTREAMIN)pvUser;
    944 
    945     if (ASMAtomicReadU32(&pStreamIn->status) != CA_STATUS_INIT)
     1329    PCOREAUDIOSTREAM pStream = (PCOREAUDIOSTREAM)pvUser;
     1330
     1331    /* Sanity. */
     1332    AssertPtr(pStream);
     1333    AssertPtr(pStream->pDrv);
     1334    Assert   (pStream->enmDir == PDMAUDIODIR_IN);
     1335    AssertPtr(pStream->Unit.pDevice);
     1336
     1337    if (ASMAtomicReadU32(&pStream->status) != COREAUDIOSTATUS_INIT)
    9461338        return noErr;
    947 
    948     PCOREAUDIOCONVCBCTX pConvCbCtx = &pStreamIn->convCbCtx;
    9491339
    9501340    OSStatus err = noErr;
    9511341    int rc = VINF_SUCCESS;
    9521342
    953     Assert(pConvCbCtx->bufLstSrc.mNumberBuffers == 1);
    954     AudioBuffer *pSrcBuf = &pConvCbCtx->bufLstSrc.mBuffers[0];
    955 
    956     pConvCbCtx->uPacketCnt = cFrames / pConvCbCtx->asbdSrc.mFramesPerPacket;
    957     pConvCbCtx->uPacketIdx = 0;
    958 
    959     AudioConverterReset(pStreamIn->pConverter);
    960 
    961     Log3Func(("cFrames=%RU32 (%RU32 frames per packet) -> %RU32 packets\n",
    962                cFrames, pConvCbCtx->asbdSrc.mFramesPerPacket, pConvCbCtx->uPacketCnt));
     1343    AudioBufferList srcBufLst;
     1344    RT_ZERO(srcBufLst);
    9631345
    9641346    do
    9651347    {
     1348#ifdef DEBUG
     1349        AudioStreamBasicDescription asbdIn;
     1350        UInt32 uSize = sizeof(asbdIn);
     1351        AudioUnitGetProperty(pStream->Unit.audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input,
     1352                             1, &asbdIn, &uSize);
     1353        coreAudioPrintASBD("DevIn",  &asbdIn);
     1354
     1355        AudioStreamBasicDescription asbdOut;
     1356        uSize = sizeof(asbdOut);
     1357        AudioUnitGetProperty(pStream->Unit.audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output,
     1358                             1, &asbdOut, &uSize);
     1359        coreAudioPrintASBD("DevOut", &asbdOut);
     1360#endif
     1361
     1362#ifdef VBOX_WITH_AUDIO_CA_CONVERTER
    9661363        /* Are we using a converter? */
    967         if (pStreamIn->pConverter)
    968         {
    969             pSrcBuf->mNumberChannels = pConvCbCtx->asbdSrc.mChannelsPerFrame;
    970             pSrcBuf->mDataByteSize   = pConvCbCtx->asbdSrc.mBytesPerFrame * cFrames;
    971             pSrcBuf->mData           = RTMemAllocZ(pSrcBuf->mDataByteSize);
    972             if (!pSrcBuf->mData)
     1364        if (pStreamIn->ConverterRef)
     1365        {
     1366            PCOREAUDIOCONVCBCTX pConvCbCtx = &pStreamIn->convCbCtx;
     1367
     1368            AudioStreamBasicDescription *pSrcASBD =  &pConvCbCtx->asbdSrc;
     1369            AudioStreamBasicDescription *pDstASBD =  &pConvCbCtx->asbdDst;
     1370# ifdef DEBUG
     1371            coreAudioPrintASBD("Src", pSrcASBD);
     1372            coreAudioPrintASBD("Dst", pDstASBD);
     1373# endif
     1374            /* Initialize source list buffer. */
     1375            srcBufLst.mNumberBuffers = 1;
     1376
     1377            /* Initialize the first buffer. */
     1378            srcBufLst.mBuffers[0].mNumberChannels = pSrcASBD->mChannelsPerFrame;
     1379            srcBufLst.mBuffers[0].mDataByteSize   = pSrcASBD->mBytesPerFrame * cFrames;
     1380            srcBufLst.mBuffers[0].mData           = RTMemAllocZ(srcBufLst.mBuffers[0].mDataByteSize);
     1381            if (!srcBufLst.mBuffers[0].mData)
    9731382            {
    9741383                rc = VERR_NO_MEMORY;
     
    9761385            }
    9771386
     1387        #if 0
     1388            /* Initialize the second buffer. */
     1389            srcBufLst.mBuffers[1].mNumberChannels = 1; //pSrcASBD->mChannelsPerFrame;
     1390            srcBufLst.mBuffers[1].mDataByteSize   = pSrcASBD->mBytesPerFrame * cFrames;
     1391            srcBufLst.mBuffers[1].mData           = RTMemAllocZ(srcBufLst.mBuffers[1].mDataByteSize);
     1392            if (!srcBufLst.mBuffers[1].mData)
     1393            {
     1394                rc = VERR_NO_MEMORY;
     1395                break;
     1396            }
     1397        #endif
     1398
     1399            /* Set the buffer list for our callback context. */
     1400            pConvCbCtx->pBufLstSrc = &srcBufLst;
     1401
     1402            /* Sanity. */
     1403            AssertPtr(pConvCbCtx->pBufLstSrc);
     1404            Assert(pConvCbCtx->pBufLstSrc->mNumberBuffers >= 1);
     1405
     1406            /* Get the first buffer. */
     1407            AudioBuffer *pSrcBuf   = &srcBufLst.mBuffers[0];
     1408
     1409            Log3Func(("pSrcBuf->mDataByteSize1=%RU32\n", pSrcBuf->mDataByteSize));
     1410
    9781411            /* First, render the source data as usual. */
    979             err = AudioUnitRender(pStreamIn->audioUnit, pActionFlags, pAudioTS, uBusID, cFrames, &pConvCbCtx->bufLstSrc);
     1412            err = AudioUnitRender(pStreamIn->audioUnit, pActionFlags, pAudioTS, uBusID, cFrames,
     1413                                  &srcBufLst);
    9801414            if (err != noErr)
    9811415            {
    982                 LogRel2(("CoreAudio: Failed rendering converted audio input data (%RI32)\n", err));
     1416                if (pConvCbCtx->cErrors < 32) /** @todo Make this configurable. */
     1417                {
     1418                    LogRel2(("CoreAudio: Failed rendering converted audio input data (%RI32:%c%c%c%c)\n", err,
     1419                             RT_BYTE4(err), RT_BYTE3(err), RT_BYTE2(err), RT_BYTE1(err)));
     1420                    pConvCbCtx->cErrors++;
     1421                }
     1422
     1423                rc = VERR_IO_GEN_FAILURE;
     1424                break;
     1425            }
     1426
     1427            /* Note: pSrcBuf->mDataByteSize can have changed after calling AudioUnitRender above! */
     1428            Log3Func(("pSrcBuf->mDataByteSize2=%RU32\n", pSrcBuf->mDataByteSize));
     1429
     1430# ifdef DEBUG_DUMP_PCM_DATA
     1431            RTFILE fh;
     1432            rc = RTFileOpen(&fh, DEBUG_DUMP_PCM_DATA_PATH "ca-recording-cb-src.pcm",
     1433                            RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
     1434            if (RT_SUCCESS(rc))
     1435            {
     1436                RTFileWrite(fh, pSrcBuf->mData, pSrcBuf->mDataByteSize, NULL);
     1437                RTFileClose(fh);
     1438            }
     1439            else
     1440                AssertFailed();
     1441# endif
     1442            AudioBufferList dstBufLst;
     1443            RT_ZERO(dstBufLst);
     1444
     1445            dstBufLst.mNumberBuffers = 1; /* We only use one buffer at once. */
     1446
     1447            AudioBuffer *pDstBuf = &dstBufLst.mBuffers[0];
     1448
     1449            UInt32 cbDst = pDstASBD->mBytesPerFrame * cFrames;
     1450            void  *pvDst = RTMemAlloc(cbDst);
     1451            if (!pvDst)
     1452            {
     1453                rc = VERR_NO_MEMORY;
     1454                break;
     1455            }
     1456
     1457            pDstBuf->mDataByteSize = cbDst;
     1458            pDstBuf->mData         = pvDst;
     1459
     1460            AudioConverterReset(pStreamIn->ConverterRef);
     1461
     1462            Log3Func(("cbSrcBufSize=%RU32 (BPF=%RU32), cbDstBufSize=%RU32 (BPF=%RU32)\n",
     1463                      pSrcBuf->mDataByteSize, pSrcASBD->mBytesPerFrame,
     1464                      pDstBuf->mDataByteSize, pDstASBD->mBytesPerFrame));
     1465
     1466            if (pSrcASBD->mSampleRate == pDstASBD->mSampleRate)
     1467            {
     1468                err = AudioConverterConvertBuffer(pStreamIn->ConverterRef,
     1469                                                #if 0
     1470                                                  cbT1, pvT1, &cbT2, pvT2);
     1471                                                #else
     1472                                                  pSrcBuf->mDataByteSize, pSrcBuf->mData /* Input */,
     1473                                                  &cbDst, pvDst                          /* Output */);
     1474                                                #endif
     1475                if (err != noErr)
     1476                {
     1477                    if (pConvCbCtx->cErrors < 32) /** @todo Make this configurable. */
     1478                    {
     1479                        LogRel2(("CoreAudio: Failed to convert audio input data (%RI32:%c%c%c%c)\n", err,
     1480                                 RT_BYTE4(err), RT_BYTE3(err), RT_BYTE2(err), RT_BYTE1(err)));
     1481                        pConvCbCtx->cErrors++;
     1482                    }
     1483
     1484                    rc = VERR_IO_GEN_FAILURE;
     1485                    break;
     1486                }
     1487
     1488# ifdef DEBUG_DUMP_PCM_DATA
     1489                rc = RTFileOpen(&fh, DEBUG_DUMP_PCM_DATA_PATH "ca-recording-cb-conv-dst.pcm",
     1490                                RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
     1491                if (RT_SUCCESS(rc))
     1492                {
     1493                    RTFileWrite(fh, pvDst, cbDst, NULL);
     1494                    RTFileClose(fh);
     1495                }
     1496                else
     1497                    AssertFailed();
     1498# endif
     1499            }
     1500            else /* Invoke FillComplexBuffer because the sample rate is different. */
     1501            {
     1502                pConvCbCtx->uPacketCnt = pSrcBuf->mDataByteSize / pSrcASBD->mBytesPerPacket;
     1503                pConvCbCtx->uPacketIdx = 0;
     1504
     1505                Log3Func(("cFrames=%RU32 (%RU32 dest frames per packet) -> %RU32 input frames\n",
     1506                          cFrames, pDstASBD->mFramesPerPacket, pConvCbCtx->uPacketCnt));
     1507
     1508                UInt32 cPacketsToWrite = pDstBuf->mDataByteSize / pDstASBD->mBytesPerPacket;
     1509                Assert(cPacketsToWrite);
     1510
     1511                UInt32 cPacketsWritten = 0;
     1512
     1513                Log3Func(("cPacketsToWrite=%RU32\n", cPacketsToWrite));
     1514
     1515                while (cPacketsToWrite)
     1516                {
     1517                    UInt32 cPacketsIO = cPacketsToWrite;
     1518
     1519                    Log3Func(("cPacketsIO=%RU32 (In)\n", cPacketsIO));
     1520
     1521                    err = AudioConverterFillComplexBuffer(pStreamIn->ConverterRef,
     1522                                                          coreAudioConverterCb, pConvCbCtx /* pvData */,
     1523                                                          &cPacketsIO, &dstBufLst, NULL);
     1524                    if (err != noErr)
     1525                    {
     1526                        if (pConvCbCtx->cErrors < 32) /** @todo Make this configurable. */
     1527                        {
     1528                            LogRel2(("CoreAudio: Failed to convert complex audio data (%RI32:%c%c%c%c)\n", err,
     1529                                     RT_BYTE4(err), RT_BYTE3(err), RT_BYTE2(err), RT_BYTE1(err)));
     1530                            pConvCbCtx->cErrors++;
     1531                        }
     1532
     1533                        rc = VERR_IO_GEN_FAILURE;
     1534                        break;
     1535                    }
     1536
     1537                    Log3Func(("cPacketsIO=%RU32 (Out)\n", cPacketsIO));
     1538
     1539                    cPacketsWritten = cPacketsIO;
     1540
     1541                    Assert(cPacketsToWrite >= cPacketsWritten);
     1542                    cPacketsToWrite -= cPacketsWritten;
     1543
     1544                    size_t cbPacketsWritten = cPacketsWritten * pDstASBD->mBytesPerPacket;
     1545                    Log3Func(("%RU32 packets written (%zu bytes), err=%RI32\n", cPacketsWritten, cbPacketsWritten, err));
     1546
     1547                    if (!cPacketsWritten)
     1548                        break;
     1549
     1550# ifdef DEBUG_DUMP_PCM_DATA
     1551                    rc = RTFileOpen(&fh, DEBUG_DUMP_PCM_DATA_PATH "ca-recording-cb-complex-dst.pcm",
     1552                                    RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
     1553                    if (RT_SUCCESS(rc))
     1554                    {
     1555                        RTFileWrite(fh, pvDst, cbDst, NULL);
     1556                        RTFileClose(fh);
     1557                    }
     1558                    else
     1559                        AssertFailed();
     1560# endif
     1561                    size_t cbFree = RTCircBufFree(pStreamIn->pCircBuf);
     1562                    if (cbFree < cbDst)
     1563                    {
     1564                        LogRel2(("CoreAudio: Recording is lagging behind (%zu bytes available but only %zu bytes free)\n",
     1565                                 cbDst, cbFree));
     1566                        break;
     1567                    }
     1568
     1569                    size_t cbDstChunk;
     1570                    void  *puDst;
     1571                    RTCircBufAcquireWriteBlock(pStreamIn->pCircBuf, cbDst, (void **)&puDst, &cbDstChunk);
     1572
     1573                    if (cbDstChunk)
     1574                        memcpy(puDst, pvDst, cbDstChunk);
     1575
     1576                    RTCircBufReleaseWriteBlock(pStreamIn->pCircBuf, cbDstChunk);
     1577                }
     1578            }
     1579
     1580            if (pvDst)
     1581            {
     1582                RTMemFree(pvDst);
     1583                pvDst = NULL;
     1584            }
     1585        }
     1586        else /* No converter being used. */
     1587        {
     1588#endif /* VBOX_WITH_AUDIO_CA_CONVERTER */
     1589
     1590            AudioStreamBasicDescription *pStreamFmt = &pStream->Unit.streamFmt;
     1591
     1592            AssertBreakStmt(pStreamFmt->mChannelsPerFrame >= 1, rc = VERR_INVALID_PARAMETER);
     1593            AssertBreakStmt(pStreamFmt->mBytesPerFrame >= 1,    rc = VERR_INVALID_PARAMETER);
     1594
     1595            srcBufLst.mNumberBuffers = 1;
     1596
     1597            AudioBuffer *pSrcBuf = &srcBufLst.mBuffers[0];
     1598
     1599            pSrcBuf->mNumberChannels = pStreamFmt->mChannelsPerFrame;
     1600            pSrcBuf->mDataByteSize   = pStreamFmt->mBytesPerFrame * cFrames;
     1601            pSrcBuf->mData           = RTMemAlloc(pSrcBuf->mDataByteSize);
     1602            if (!pSrcBuf->mData)
     1603            {
     1604                rc = VERR_NO_MEMORY;
     1605                break;
     1606            }
     1607
     1608            err = AudioUnitRender(pStream->Unit.audioUnit, pActionFlags, pAudioTS, 1 /* Input bus */, cFrames, &srcBufLst);
     1609            if (err != noErr)
     1610            {
     1611                LogRel2(("CoreAudio: Failed rendering non-converted audio input data (%RI32)\n", err));
    9831612                rc = VERR_IO_GEN_FAILURE; /** @todo Improve this. */
    9841613                break;
    9851614            }
    986 
    987             Log3Func(("cbSrcBufSize=%RU32\n", pSrcBuf->mDataByteSize));
    9881615
    9891616#ifdef DEBUG_DUMP_PCM_DATA
     
    9991626                AssertFailed();
    10001627#endif
    1001             AudioBufferList dstBufList;
    1002 
    1003             dstBufList.mNumberBuffers = 1; /* We only use one buffer at once. */
    1004 
    1005             AudioBuffer *pDstBuf = &dstBufList.mBuffers[0];
    1006             pDstBuf->mDataByteSize   = pConvCbCtx->asbdDst.mBytesPerFrame * cFrames;
    1007             pDstBuf->mData           = RTMemAllocZ(pDstBuf->mDataByteSize);
    1008             if (!pDstBuf->mData)
    1009             {
    1010                 rc = VERR_NO_MEMORY;
    1011                 break;
    1012             }
    1013 
    1014             UInt32 cPacketsToWriteAndWritten = pConvCbCtx->uPacketCnt;
    1015             Assert(cPacketsToWriteAndWritten);
    1016 
    1017             Log3Func(("cPacketsToWrite=%RU32\n", cPacketsToWriteAndWritten));
    1018 
    1019             do
    1020             {
    1021                 err = AudioConverterFillComplexBuffer(pStreamIn->pConverter,
    1022                                                       coreAudioConverterCallback, pConvCbCtx /* pvData */,
    1023                                                       &cPacketsToWriteAndWritten, &dstBufList, NULL);
    1024 
    1025                 Log3Func(("cPacketsWritten=%RU32 (%zu bytes), err=%RI32\n",
    1026                           cPacketsToWriteAndWritten, cPacketsToWriteAndWritten * pConvCbCtx->asbdDst.mBytesPerPacket, err));
    1027 
    1028                 if (err != noErr)
    1029                 {
    1030                     LogFlowFunc(("Failed to convert audio data (%RI32:%c%c%c%c)\n", err,
    1031                                  RT_BYTE4(err), RT_BYTE3(err), RT_BYTE2(err), RT_BYTE1(err)));
    1032                     rc = VERR_IO_GEN_FAILURE;
     1628            PRTCIRCBUF pCircBuf = pStream->pCircBuf;
     1629
     1630            const uint32_t cbDataSize = pSrcBuf->mDataByteSize;
     1631            const size_t   cbBufFree  = RTCircBufFree(pCircBuf);
     1632                  size_t   cbAvail    = RT_MIN(cbDataSize, cbBufFree);
     1633
     1634            Log3Func(("cbDataSize=%RU32, cbBufFree=%zu, cbAvail=%zu\n", cbDataSize, cbBufFree, cbAvail));
     1635
     1636            /* Iterate as long as data is available. */
     1637            uint8_t *puDst = NULL;
     1638            uint32_t cbWrittenTotal = 0;
     1639            while (cbAvail)
     1640            {
     1641                /* Try to acquire the necessary space from the ring buffer. */
     1642                size_t cbToWrite = 0;
     1643                RTCircBufAcquireWriteBlock(pCircBuf, cbAvail, (void **)&puDst, &cbToWrite);
     1644                if (!cbToWrite)
    10331645                    break;
    1034                 }
    1035 
    1036                 if (cPacketsToWriteAndWritten == 0)
    1037                     break;
    1038 
    1039                 size_t cbDst = cPacketsToWriteAndWritten * pConvCbCtx->asbdDst.mBytesPerPacket;
     1646
     1647                /* Copy the data from the Core Audio buffer to the ring buffer. */
     1648                memcpy(puDst, (uint8_t *)pSrcBuf->mData + cbWrittenTotal, cbToWrite);
    10401649
    10411650#ifdef DEBUG_DUMP_PCM_DATA
     
    10441653                if (RT_SUCCESS(rc))
    10451654                {
    1046                     RTFileWrite(fh, pDstBuf->mData, cbDst, NULL);
     1655                    RTFileWrite(fh, (uint8_t *)pSrcBuf->mData + cbWrittenTotal, cbToWrite, NULL);
    10471656                    RTFileClose(fh);
    10481657                }
     
    10501659                    AssertFailed();
    10511660#endif
    1052                 size_t cbFree = RTCircBufFree(pStreamIn->pCircBuf);
    1053                 if (cbFree < cbDst)
    1054                 {
    1055                     LogRel2(("CoreAudio: Recording is lagging behind (%zu bytes available but only %zu bytes free)\n",
    1056                              cbDst, cbFree));
    1057                     break;
    1058                 }
    1059 
    1060                 size_t cbDstChunk;
    1061                 void  *puDst;
    1062                 RTCircBufAcquireWriteBlock(pStreamIn->pCircBuf, cbDst, (void **)&puDst, &cbDstChunk);
    1063 
    1064                 if (cbDstChunk)
    1065                     memcpy(puDst, pDstBuf->mData, cbDstChunk);
    1066 
    1067                 RTCircBufReleaseWriteBlock(pStreamIn->pCircBuf, cbDstChunk);
    1068 
    1069             } while (1);
    1070 
    1071             if (pDstBuf->mData)
    1072             {
    1073                 RTMemFree(pDstBuf->mData);
    1074                 pDstBuf->mData = NULL;
    1075             }
    1076         }
    1077         else /* No converter being used. */
    1078         {
    1079             AssertBreakStmt(pStreamIn->streamFormat.mChannelsPerFrame >= 1, rc = VERR_INVALID_PARAMETER);
    1080             AssertBreakStmt(pStreamIn->streamFormat.mBytesPerFrame >= 1,    rc = VERR_INVALID_PARAMETER);
    1081 
    1082             AssertBreakStmt(pSrcBuf->mNumberChannels, rc = VERR_INVALID_PARAMETER);
    1083 
    1084             pSrcBuf->mNumberChannels = pStreamIn->streamFormat.mChannelsPerFrame;
    1085             pSrcBuf->mDataByteSize   = pStreamIn->streamFormat.mBytesPerFrame * cFrames;
    1086             pSrcBuf->mData           = RTMemAlloc(pSrcBuf->mDataByteSize);
    1087             if (!pSrcBuf->mData)
    1088             {
    1089                 rc = VERR_NO_MEMORY;
    1090                 break;
    1091             }
    1092 
    1093             err = AudioUnitRender(pStreamIn->audioUnit, pActionFlags, pAudioTS, uBusID, cFrames, &pConvCbCtx->bufLstSrc);
    1094             if (err != noErr)
    1095             {
    1096                 LogRel2(("CoreAudio: Failed rendering non-coverted audio input data (%RI32)\n", err));
    1097                 rc = VERR_IO_GEN_FAILURE; /** @todo Improve this. */
    1098                 break;
    1099             }
    1100 
    1101             const uint32_t cbDataSize = pSrcBuf->mDataByteSize;
    1102             const size_t   cbBufFree  = RTCircBufFree(pStreamIn->pCircBuf);
    1103                   size_t   cbAvail    = RT_MIN(cbDataSize, cbBufFree);
    1104 
    1105             Log3Func(("cbDataSize=%RU32, cbBufFree=%zu, cbAvail=%zu\n", cbDataSize, cbBufFree, cbAvail));
    1106 
    1107             /* Iterate as long as data is available. */
    1108             uint8_t *puDst = NULL;
    1109             uint32_t cbWrittenTotal = 0;
    1110             while (cbAvail)
    1111             {
    1112                 /* Try to acquire the necessary space from the ring buffer. */
    1113                 size_t cbToWrite = 0;
    1114                 RTCircBufAcquireWriteBlock(pStreamIn->pCircBuf, cbAvail, (void **)&puDst, &cbToWrite);
    1115                 if (!cbToWrite)
    1116                     break;
    1117 
    1118                 /* Copy the data from the Core Audio buffer to the ring buffer. */
    1119                 memcpy(puDst, (uint8_t *)pSrcBuf->mData + cbWrittenTotal, cbToWrite);
    1120 
    11211661                /* Release the ring buffer, so the main thread could start reading this data. */
    1122                 RTCircBufReleaseWriteBlock(pStreamIn->pCircBuf, cbToWrite);
     1662                RTCircBufReleaseWriteBlock(pCircBuf, cbToWrite);
    11231663
    11241664                cbWrittenTotal += cbToWrite;
     
    11291669
    11301670            Log3Func(("cbWrittenTotal=%RU32, cbLeft=%zu\n", cbWrittenTotal, cbAvail));
    1131         }
     1671
     1672#ifdef VBOX_WITH_AUDIO_CA_CONVERTER
     1673        }
     1674#endif
    11321675
    11331676    } while (0);
    11341677
    1135     if (pSrcBuf->mData)
    1136     {
    1137         RTMemFree(pSrcBuf->mData);
    1138         pSrcBuf->mData = NULL;
     1678    for (UInt32 i = 0; i < srcBufLst.mNumberBuffers; i++)
     1679    {
     1680        if (srcBufLst.mBuffers[i].mData)
     1681        {
     1682            RTMemFree(srcBufLst.mBuffers[i].mData);
     1683            srcBufLst.mBuffers[i].mData = NULL;
     1684        }
    11391685    }
    11401686
     
    11421688}
    11431689
    1144 #define CA_BREAK_STMT(stmt) if (true) \
    1145     { \
    1146         stmt; \
    1147         break; \
    1148     } else do { } while (0)
     1690
     1691/**
     1692 * Initializes a Core Audio stream.
     1693 *
     1694 * @return IPRT status code.
     1695 * @param  pThis                Driver instance.
     1696 * @param  pCAStream            Stream to initialize.
     1697 * @param  pDev                 Audio device to use for this stream.
     1698 */
     1699static int coreAudioStreamInit(PCOREAUDIOSTREAM pCAStream, PDRVHOSTCOREAUDIO pThis, PPDMAUDIODEVICE pDev)
     1700{
     1701    Assert(pCAStream->Unit.pDevice == NULL); /* Make sure no device is assigned yet. */
     1702
     1703    pCAStream->Unit.pDevice = pDev;
     1704    pCAStream->pDrv = pThis;
     1705
     1706    return VINF_SUCCESS;
     1707}
     1708
     1709# define CA_BREAK_STMT(stmt) \
     1710    stmt; \
     1711    break;
    11491712
    11501713/** @todo Eventually split up this function, as this already is huge! */
    1151 static int coreAudioInitIn(PDRVHOSTCOREAUDIO pThis, PPDMAUDIOSTREAM pStream,
    1152                            PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
    1153 {
    1154     RT_NOREF(pThis);
    1155 
     1714static int coreAudioStreamInitIn(PCOREAUDIOSTREAM pCAStream, PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
     1715{
    11561716    int rc = VINF_SUCCESS;
    11571717
    1158     PCOREAUDIOSTREAMIN pStreamIn = (PCOREAUDIOSTREAMIN)pStream;
    11591718    UInt32 cSamples = 0;
    11601719
    11611720    OSStatus err = noErr;
    1162     UInt32 uSize = 0;
    1163 
    1164     AudioDeviceID deviceID = pStreamIn->deviceID;
    1165     if (deviceID == kAudioDeviceUnknown)
    1166     {
    1167         /* Fetch the default audio recording device currently in use. */
    1168         AudioObjectPropertyAddress propAdr = { kAudioHardwarePropertyDefaultInputDevice,
    1169                                                kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
    1170         uSize = sizeof(deviceID);
    1171         err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &propAdr, 0, NULL, &uSize,  &deviceID);
    1172         if (err != noErr)
    1173         {
    1174             LogFlowFunc(("CoreAudio: Unable to determine default recording device (%RI32)\n", err));
    1175             return VERR_AUDIO_NO_FREE_INPUT_STREAMS;
    1176         }
    1177     }
    1178 
    1179     if (deviceID == kAudioDeviceUnknown)
    1180     {
    1181         LogFlowFunc(("No default recording device found\n"));
    1182         return VERR_AUDIO_NO_FREE_INPUT_STREAMS;
    1183     }
     1721
     1722    PPDMAUDIODEVICE pDev = pCAStream->Unit.pDevice;
     1723    AssertPtr(pDev);
     1724
     1725    PCOREAUDIODEVICEDATA pData = (PCOREAUDIODEVICEDATA)pDev->pvData;
     1726    AssertPtr(pData);
     1727
     1728    AudioDeviceID deviceID = pData->deviceID;
     1729    Assert(deviceID != kAudioDeviceUnknown);
    11841730
    11851731    do
    11861732    {
    1187         ASMAtomicXchgU32(&pStreamIn->status, CA_STATUS_IN_INIT);
    1188 
    1189         /* Assign device ID. */
    1190         pStreamIn->deviceID = deviceID;
    1191 
    1192         /*
    1193          * Try to get the name of the recording device and log it. It's not fatal if it fails.
    1194          */
    1195         CFStringRef strTemp;
    1196 
    1197         AudioObjectPropertyAddress propAdr = { kAudioObjectPropertyName, kAudioObjectPropertyScopeGlobal,
    1198                                                kAudioObjectPropertyElementMaster };
    1199         uSize = sizeof(CFStringRef);
    1200         err = AudioObjectGetPropertyData(pStreamIn->deviceID, &propAdr, 0, NULL, &uSize, &strTemp);
    1201         if (err == noErr)
    1202         {
    1203             char *pszDevName = NULL;
    1204             err = coreAudioCFStringToCString(strTemp, &pszDevName);
    1205             if (err == noErr)
    1206             {
    1207                 CFRelease(strTemp);
    1208 
    1209                 /* Get the device' UUID. */
    1210                 propAdr.mSelector = kAudioDevicePropertyDeviceUID;
    1211                 err = AudioObjectGetPropertyData(pStreamIn->deviceID, &propAdr, 0, NULL, &uSize, &strTemp);
    1212                 if (err == noErr)
    1213                 {
    1214                     char *pszUID = NULL;
    1215 
    1216                     err = coreAudioCFStringToCString(strTemp, &pszUID);
    1217                     if (err == noErr)
    1218                     {
    1219                         CFRelease(strTemp);
    1220                         LogRel(("CoreAudio: Using recording device: %s (UID: %s)\n", pszDevName, pszUID));
    1221 
    1222                         RTMemFree(pszUID);
    1223                     }
    1224                 }
    1225 
    1226                 RTMemFree(pszDevName);
    1227             }
    1228         }
    1229         else
    1230         {
    1231             /* This is not fatal, can happen for some Macs. */
    1232             LogRel2(("CoreAudio: Unable to determine recording device name (%RI32)\n", err));
    1233         }
     1733        ASMAtomicXchgU32(&pCAStream->status, COREAUDIOSTATUS_IN_INIT);
    12341734
    12351735        /* Get the default frames buffer size, so that we can setup our internal buffers. */
    12361736        UInt32 cFrames;
    1237         uSize = sizeof(cFrames);
     1737        UInt32 uSize = sizeof(cFrames);
     1738
     1739        AudioObjectPropertyAddress propAdr;
    12381740        propAdr.mSelector = kAudioDevicePropertyBufferFrameSize;
    12391741        propAdr.mScope    = kAudioDevicePropertyScopeInput;
    1240         err = AudioObjectGetPropertyData(pStreamIn->deviceID, &propAdr, 0, NULL, &uSize, &cFrames);
     1742        propAdr.mElement  = kAudioObjectPropertyElementMaster;
     1743        err = AudioObjectGetPropertyData(deviceID, &propAdr, 0, NULL, &uSize, &cFrames);
    12411744        if (err != noErr)
    12421745        {
     
    12481751
    12491752        /* Set the frame buffer size and honor any minimum/maximum restrictions on the device. */
    1250         err = coreAudioSetFrameBufferSize(pStreamIn->deviceID, true /* fInput */, cFrames, &cFrames);
     1753        err = coreAudioSetFrameBufferSize(deviceID, true /* fInput */, cFrames, &cFrames);
    12511754        if (err != noErr)
    12521755        {
     
    12731776
    12741777        /* Open the default HAL output component. */
    1275         err = AudioComponentInstanceNew(cp, &pStreamIn->audioUnit);
     1778        err = AudioComponentInstanceNew(cp, &pCAStream->Unit.audioUnit);
    12761779        if (err != noErr)
    12771780        {
     
    12821785        /* Switch the I/O mode for input to on. */
    12831786        UInt32 uFlag = 1;
    1284         err = AudioUnitSetProperty(pStreamIn->audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input,
     1787        err = AudioUnitSetProperty(pCAStream->Unit.audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input,
    12851788                                   1, &uFlag, sizeof(uFlag));
    12861789        if (err != noErr)
     
    12921795        /* Switch the I/O mode for output to off. This is important, as this is a pure input stream. */
    12931796        uFlag = 0;
    1294         err = AudioUnitSetProperty(pStreamIn->audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output,
     1797        err = AudioUnitSetProperty(pCAStream->Unit.audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output,
    12951798                                   0, &uFlag, sizeof(uFlag));
    12961799        if (err != noErr)
     
    13011804
    13021805        /* Set the default audio recording device as the device for the new AudioUnit. */
    1303         err = AudioUnitSetProperty(pStreamIn->audioUnit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global,
    1304                                    0, &pStreamIn->deviceID, sizeof(pStreamIn->deviceID));
     1806        err = AudioUnitSetProperty(pCAStream->Unit.audioUnit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global,
     1807                                   0, &deviceID, sizeof(deviceID));
    13051808        if (err != noErr)
    13061809        {
    1307             LogRel(("CoreAudio: Failed to set current device (%RI32)\n", err));
     1810            LogRel(("CoreAudio: Failed to set current input device (%RI32)\n", err));
    13081811            CA_BREAK_STMT(rc = VERR_AUDIO_BACKEND_INIT_FAILED);
    13091812        }
     
    13151818        AURenderCallbackStruct cb;
    13161819        RT_ZERO(cb);
    1317         cb.inputProc       = coreAudioRecordingCb;
    1318         cb.inputProcRefCon = pStreamIn;
    1319 
    1320         err = AudioUnitSetProperty(pStreamIn->audioUnit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global,
     1820        cb.inputProc       = coreAudioCaptureCb;
     1821        cb.inputProcRefCon = pCAStream;
     1822
     1823        err = AudioUnitSetProperty(pCAStream->Unit.audioUnit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global,
    13211824                                   0, &cb, sizeof(cb));
    13221825        if (err != noErr)
     
    13261829        }
    13271830
    1328         /* Fetch the current stream format of the device. */
    1329         RT_ZERO(pStreamIn->deviceFormat);
    1330         uSize = sizeof(pStreamIn->deviceFormat);
    1331         err = AudioUnitGetProperty(pStreamIn->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input,
    1332                                    1, &pStreamIn->deviceFormat, &uSize);
     1831        /* Create the recording device's out format based on our required audio settings. */
     1832        AudioStreamBasicDescription reqFmt;
     1833        rc = coreAudioStreamCfgToASBD(pCfgReq, &reqFmt);
     1834        if (RT_FAILURE(rc))
     1835        {
     1836            LogRel(("CoreAudio: Failed to convert requested input format to native format (%Rrc)\n", rc));
     1837            CA_BREAK_STMT(rc = VERR_AUDIO_BACKEND_INIT_FAILED);
     1838        }
     1839
     1840        coreAudioPrintASBD("Requested stream input format", &reqFmt);
     1841
     1842        /* Fetch the input format of the recording device. */
     1843        AudioStreamBasicDescription devInFmt;
     1844        RT_ZERO(devInFmt);
     1845        uSize = sizeof(devInFmt);
     1846        err = AudioUnitGetProperty(pCAStream->Unit.audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input,
     1847                                   1, &devInFmt, &uSize);
    13331848        if (err != noErr)
    13341849        {
    1335             LogRel(("CoreAudio: Failed to get device format (%RI32)\n", err));
     1850            LogRel(("CoreAudio: Failed to get input device input format (%RI32)\n", err));
    13361851            CA_BREAK_STMT(rc = VERR_AUDIO_BACKEND_INIT_FAILED);
    13371852        }
    13381853
    1339         /* Create an AudioStreamBasicDescription based on our required audio settings. */
    1340         RT_ZERO(pStreamIn->streamFormat);
    1341         coreAudioStreamCfgToASBD(pCfgReq, &pStreamIn->streamFormat);
    1342 
    1343         coreAudioPrintASBD("Recording device", &pStreamIn->deviceFormat);
    1344         coreAudioPrintASBD("Recording stream", &pStreamIn->streamFormat);
    1345 
    1346         /* If the frequency of the device is different from the requested one we
    1347          * need a converter. The same count if the number of channels is different. */
    1348         if (   pStreamIn->deviceFormat.mSampleRate       != pStreamIn->streamFormat.mSampleRate
    1349             || pStreamIn->deviceFormat.mChannelsPerFrame != pStreamIn->streamFormat.mChannelsPerFrame)
     1854        coreAudioPrintASBD("Input device in (initial)", &devInFmt);
     1855
     1856        /* Fetch the output format of the recording device. */
     1857        AudioStreamBasicDescription devOutFmt;
     1858        RT_ZERO(devOutFmt);
     1859        uSize = sizeof(devOutFmt);
     1860        err = AudioUnitGetProperty(pCAStream->Unit.audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output,
     1861                                   1, &devOutFmt, &uSize);
     1862        if (err != noErr)
     1863        {
     1864            LogRel(("CoreAudio: Failed to get input device output format (%RI32)\n", err));
     1865            CA_BREAK_STMT(rc = VERR_AUDIO_BACKEND_INIT_FAILED);
     1866        }
     1867
     1868        coreAudioPrintASBD("Input device out (initial)", &devOutFmt);
     1869
     1870        /* Set the output format for the input device so that it matches the initial input format.
     1871         * This apparently is needed for some picky / buggy USB headsets. */
     1872
     1873        /*
     1874         * The only thing we tweak here is the actual format flags: A lot of USB headsets tend
     1875         * to have float PCM data, which we can't handle (yet).
     1876         *
     1877         * So set this as signed integers in a packed, non-iterleaved format.
     1878         */
     1879        devInFmt.mFormatFlags =   kAudioFormatFlagIsSignedInteger
     1880                                | kAudioFormatFlagIsPacked;
     1881
     1882        err = AudioUnitSetProperty(pCAStream->Unit.audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output,
     1883                                   1, &devInFmt, sizeof(devInFmt));
     1884        if (err != noErr)
     1885        {
     1886            LogRel(("CoreAudio: Failed to set new output format for input device (%RI32)\n", err));
     1887            CA_BREAK_STMT(rc = VERR_AUDIO_BACKEND_INIT_FAILED);
     1888        }
     1889
     1890        /*
     1891         * Also set the frame buffer size of the device on our AudioUnit. This
     1892         * should make sure that the frames count which we receive in the render
     1893         * thread is as we like.
     1894         */
     1895        err = AudioUnitSetProperty(pCAStream->Unit.audioUnit, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global,
     1896                                   1, &cFrames, sizeof(cFrames));
     1897        if (err != noErr)
     1898        {
     1899            LogRel(("CoreAudio: Failed to set maximum frame buffer size for input stream (%RI32)\n", err));
     1900            CA_BREAK_STMT(rc = VERR_AUDIO_BACKEND_INIT_FAILED);
     1901        }
     1902
     1903        /*
     1904         * Initialize the new AudioUnit.
     1905         */
     1906        err = AudioUnitInitialize(pCAStream->Unit.audioUnit);
     1907        if (err != noErr)
     1908        {
     1909            LogRel(("CoreAudio: Failed to initialize input audio device (%RI32)\n", err));
     1910            CA_BREAK_STMT(rc = VERR_AUDIO_BACKEND_INIT_FAILED);
     1911        }
     1912
     1913        /* Get final input format afer initialization. */
     1914        uSize = sizeof(devInFmt);
     1915        err = AudioUnitGetProperty(pCAStream->Unit.audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input,
     1916                                   1, &devInFmt, &uSize);
     1917        if (err != noErr)
     1918        {
     1919            LogRel(("CoreAudio: Failed to re-getting input device input format (%RI32)\n", err));
     1920            CA_BREAK_STMT(rc = VERR_AUDIO_BACKEND_INIT_FAILED);
     1921        }
     1922
     1923        /* Print the device/stream formats again after the audio unit has been initialized.
     1924         * Note that the formats could have changed now. */
     1925        coreAudioPrintASBD("Input device in (after initialization)", &devInFmt);
     1926
     1927        /* Get final output format afer initialization. */
     1928        uSize = sizeof(devOutFmt);
     1929        err = AudioUnitGetProperty(pCAStream->Unit.audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output,
     1930                                   1, &devOutFmt, &uSize);
     1931        if (err != noErr)
     1932        {
     1933            LogRel(("CoreAudio: Failed to re-getting input device output format (%RI32)\n", err));
     1934            CA_BREAK_STMT(rc = VERR_AUDIO_BACKEND_INIT_FAILED);
     1935        }
     1936
     1937        /* Print the device/stream formats again after the audio unit has been initialized.
     1938         * Note that the formats could have changed now. */
     1939        coreAudioPrintASBD("Input device out (after initialization)", &devOutFmt);
     1940
     1941#ifdef VBOX_WITH_AUDIO_CA_CONVERTER
     1942
     1943        /* If the frequency of the device' output format different from the requested one we
     1944         * need a converter. The same counts if the number of channels or the bits per channel are different. */
     1945        if (   devOutFmt.mChannelsPerFrame != reqFmt.mChannelsPerFrame
     1946            || devOutFmt.mSampleRate       != reqFmt.mSampleRate)
    13501947        {
    13511948            LogRel2(("CoreAudio: Input converter is active\n"));
    13521949
    1353             err = AudioConverterNew(&pStreamIn->deviceFormat, &pStreamIn->streamFormat, &pStreamIn->pConverter);
     1950            err = AudioConverterNew(&devOutFmt /* Input */, &reqFmt /* Output */, &pCAStream->In.ConverterRef);
    13541951            if (RT_UNLIKELY(err != noErr))
    13551952            {
     
    13581955            }
    13591956
    1360             if (   pStreamIn->deviceFormat.mChannelsPerFrame == 1 /* Mono */
    1361                 && pStreamIn->streamFormat.mChannelsPerFrame == 2 /* Stereo */)
     1957            if (   devOutFmt.mChannelsPerFrame == 1 /* Mono */
     1958                && reqFmt.mChannelsPerFrame    == 2 /* Stereo */)
    13621959            {
    13631960                LogRel2(("CoreAudio: Mono to stereo conversion active\n"));
     
    13721969                const SInt32 channelMap[2] = {0, 0}; /* Channel map for mono -> stereo. */
    13731970
    1374                 err = AudioConverterSetProperty(pStreamIn->pConverter, kAudioConverterChannelMap, sizeof(channelMap), channelMap);
     1971                err = AudioConverterSetProperty(pCAStream->In.ConverterRef, kAudioConverterChannelMap, sizeof(channelMap), channelMap);
    13751972                if (err != noErr)
    13761973                {
     
    13821979            /* Set sample rate converter quality to maximum. */
    13831980            uFlag = kAudioConverterQuality_Max;
    1384             err = AudioConverterSetProperty(pStreamIn->pConverter, kAudioConverterSampleRateConverterQuality,
     1981            err = AudioConverterSetProperty(pCAStream->In.ConverterRef, kAudioConverterSampleRateConverterQuality,
    13851982                                            sizeof(uFlag), &uFlag);
    13861983            if (err != noErr)
     
    13891986            uSize = sizeof(UInt32);
    13901987            UInt32 maxOutputSize;
    1391             err = AudioConverterGetProperty(pStreamIn->pConverter, kAudioConverterPropertyMaximumOutputPacketSize,
     1988            err = AudioConverterGetProperty(pStreamIn->ConverterRef, kAudioConverterPropertyMaximumOutputPacketSize,
    13921989                                            &uSize, &maxOutputSize);
    13931990            if (RT_UNLIKELY(err != noErr))
     
    13981995
    13991996            LogFunc(("Maximum converter packet output size is: %RI32\n", maxOutputSize));
    1400 
    1401             /* Set the input (source) format, that is, the format the device is recording data with. */
    1402             err = AudioUnitSetProperty(pStreamIn->audioUnit,
    1403                                        kAudioUnitProperty_StreamFormat,
    1404                                        kAudioUnitScope_Input,
    1405                                        1,
    1406                                        &pStreamIn->deviceFormat,
    1407                                        sizeof(pStreamIn->deviceFormat));
    1408             if (RT_UNLIKELY(err != noErr))
    1409             {
    1410                 LogRel(("CoreAudio: Failed to set device input format (%RI32)\n", err));
    1411                 CA_BREAK_STMT(rc = VERR_AUDIO_BACKEND_INIT_FAILED);
    1412             }
    1413 
    1414             /* Set the output (target) format, that is, the format we created the input stream with. */
    1415             err = AudioUnitSetProperty(pStreamIn->audioUnit,
    1416                                        kAudioUnitProperty_StreamFormat,
    1417                                        kAudioUnitScope_Output,
    1418                                        1,
    1419                                        &pStreamIn->deviceFormat,
    1420                                        sizeof(pStreamIn->deviceFormat));
    1421             if (RT_UNLIKELY(err != noErr))
    1422             {
    1423                 LogRel(("CoreAudio: Failed to set stream output format (%RI32)\n", err));
    1424                 CA_BREAK_STMT(rc = VERR_AUDIO_BACKEND_INIT_FAILED);
    1425             }
     1997        }
     1998#endif /* VBOX_WITH_AUDIO_CA_CONVERTER */
     1999
     2000#ifdef VBOX_WITH_AUDIO_CA_CONVERTER
     2001        if (pCAStream->In.ConverterRef)
     2002        {
     2003            /* Save the requested format as our stream format. */
     2004            memcpy(&pCAStream->Unit.streamFmt, &reqFmt, sizeof(AudioStreamBasicDescription));
    14262005        }
    14272006        else
    14282007        {
    1429             /* Set the new output format description for the input stream. */
    1430             err = AudioUnitSetProperty(pStreamIn->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output,
    1431                                        1, &pStreamIn->streamFormat, sizeof(pStreamIn->streamFormat));
    1432             if (err != noErr)
    1433             {
    1434                 LogRel(("CoreAudio: Failed to set output format for input stream (%RI32)\n", err));
    1435                 CA_BREAK_STMT(rc = VERR_AUDIO_BACKEND_INIT_FAILED);
    1436             }
    1437         }
    1438 
    1439         /*
    1440          * Also set the frame buffer size off the device on our AudioUnit. This
    1441          * should make sure that the frames count which we receive in the render
    1442          * thread is as we like.
    1443          */
    1444         err = AudioUnitSetProperty(pStreamIn->audioUnit, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global,
    1445                                    1, &cFrames, sizeof(cFrames));
    1446         if (err != noErr)
    1447         {
    1448             LogRel(("CoreAudio: Failed to set maximum frame buffer size for input stream (%RI32)\n", err));
    1449             CA_BREAK_STMT(rc = VERR_AUDIO_BACKEND_INIT_FAILED);
    1450         }
    1451 
    1452         /* Finally initialize the new AudioUnit. */
    1453         err = AudioUnitInitialize(pStreamIn->audioUnit);
    1454         if (err != noErr)
    1455         {
    1456             LogRel(("CoreAudio: Failed to initialize audio unit for input stream (%RI32)\n", err));
    1457             CA_BREAK_STMT(rc = VERR_AUDIO_BACKEND_INIT_FAILED);
    1458         }
    1459 
    1460         uSize = sizeof(pStreamIn->deviceFormat);
    1461         err = AudioUnitGetProperty(pStreamIn->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output,
    1462                                    1, &pStreamIn->deviceFormat, &uSize);
    1463         if (err != noErr)
    1464         {
    1465             LogRel(("CoreAudio: Failed to get recording device format (%RI32)\n", err));
    1466             CA_BREAK_STMT(rc = VERR_AUDIO_BACKEND_INIT_FAILED);
    1467         }
    1468 
     2008#endif /* VBOX_WITH_AUDIO_CA_CONVERTER */
     2009
     2010            /* Save the final output format as our stream format. */
     2011            memcpy(&pCAStream->Unit.streamFmt, &devOutFmt, sizeof(AudioStreamBasicDescription));
     2012
     2013#ifdef VBOX_WITH_AUDIO_CA_CONVERTER
     2014        }
     2015#endif
    14692016        /*
    14702017         * There are buggy devices (e.g. my Bluetooth headset) which doesn't honor
     
    14732020         */
    14742021        uSize = sizeof(cFrames);
    1475         err = AudioUnitGetProperty(pStreamIn->audioUnit, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global,
     2022        err = AudioUnitGetProperty(pCAStream->Unit.audioUnit, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global,
    14762023                                   0, &cFrames, &uSize);
    14772024        if (err != noErr)
     
    14812028        }
    14822029
    1483         /* Destroy any former internal ring buffer. */
    1484         if (pStreamIn->pCircBuf)
    1485         {
    1486             RTCircBufDestroy(pStreamIn->pCircBuf);
    1487             pStreamIn->pCircBuf = NULL;
    1488         }
    1489 
    1490         coreAudioUninitConvCbCtx(&pStreamIn->convCbCtx);
    1491 
    14922030        /* Calculate the ratio between the device and the stream sample rate. */
    1493         pStreamIn->sampleRatio = pStreamIn->streamFormat.mSampleRate / pStreamIn->deviceFormat.mSampleRate;
     2031        pCAStream->In.sampleRatio = devOutFmt.mSampleRate / devInFmt.mSampleRate;
    14942032
    14952033        /*
     
    15012039         */
    15022040        cSamples = RT_MAX(cFrames,
    1503                           (cFrames * pStreamIn->deviceFormat.mBytesPerFrame * pStreamIn->sampleRatio)
    1504                            / pStreamIn->streamFormat.mBytesPerFrame)
    1505                            * pStreamIn->streamFormat.mChannelsPerFrame;
     2041                          (cFrames * reqFmt.mBytesPerFrame * pCAStream->In.sampleRatio)
     2042                           / reqFmt.mBytesPerFrame)
     2043                           * reqFmt.mChannelsPerFrame;
    15062044        if (!cSamples)
    15072045        {
     
    15102048        }
    15112049
    1512         PDMAUDIOPCMPROPS PCMProps;
    1513         int rc2 = DrvAudioHlpStreamCfgToProps(pCfgAcq, &PCMProps);
    1514         AssertRC(rc2);
    1515 
    1516         rc = RTCircBufCreate(&pStreamIn->pCircBuf, cSamples << PCMProps.cShift);
     2050        rc = RTCircBufCreate(&pCAStream->pCircBuf, cSamples << 1 /*pHstStrmIn->Props.cShift*/); /** @todo FIX THIS !!! */
    15172051        if (RT_FAILURE(rc))
    15182052            break;
    15192053
     2054#ifdef VBOX_WITH_AUDIO_CA_CONVERTER
    15202055        /* Init the converter callback context. */
    1521         rc = coreAudioInitConvCbCtx(&pStreamIn->convCbCtx,
    1522                                     &pStreamIn->deviceFormat /* Source */, &pStreamIn->streamFormat /* Dest */);
    1523 
    1524         if (RT_SUCCESS(rc))
    1525         {
    1526 #ifdef DEBUG
    1527             propAdr.mSelector = kAudioDeviceProcessorOverload;
    1528             propAdr.mScope    = kAudioUnitScope_Global;
    1529             err = AudioObjectAddPropertyListener(pStreamIn->deviceID, &propAdr,
    1530                                                  coreAudioRecordingAudioDevicePropertyChanged, (void *)pStreamIn);
    1531             if (RT_UNLIKELY(err != noErr))
    1532                 LogRel2(("CoreAudio: Failed to add the processor overload listener for input stream (%RI32)\n", err));
    1533 #endif /* DEBUG */
    1534             propAdr.mSelector = kAudioDevicePropertyNominalSampleRate;
    1535             propAdr.mScope    = kAudioUnitScope_Global;
    1536             err = AudioObjectAddPropertyListener(pStreamIn->deviceID, &propAdr,
    1537                                                  coreAudioRecordingAudioDevicePropertyChanged, (void *)pStreamIn);
    1538             /* Not fatal. */
    1539             if (RT_UNLIKELY(err != noErr))
    1540                 LogRel2(("CoreAudio: Failed to register sample rate changed listener for input stream (%RI32)\n", err));
    1541         }
     2056
     2057        /* As source, use the input device' output format,
     2058         * as destination, use the initially requested format. */
     2059        rc = coreAudioInitConvCbCtx(&pCAStream->In.convCbCtx, pCAStream,
     2060                                    &devOutFmt /* Source */, &reqFmt /* Dest */);
     2061#endif
    15422062
    15432063    } while (0);
     
    15452065    if (RT_SUCCESS(rc))
    15462066    {
    1547         ASMAtomicXchgU32(&pStreamIn->status, CA_STATUS_INIT);
    1548 
    1549         LogFunc(("cSamples=%RU32\n", cSamples));
    1550 
    1551         if (pCfgAcq)
    1552             pCfgAcq->cSampleBufferSize = cSamples;
     2067        pCAStream->enmDir = PDMAUDIODIR_IN;
     2068
     2069        rc = coreAudioASBDToStreamCfg(&pCAStream->Unit.streamFmt, pCfgAcq);
     2070        AssertRC(rc);
     2071
     2072        ASMAtomicXchgU32(&pCAStream->status, COREAUDIOSTATUS_INIT);
     2073
     2074        pCfgAcq->cSampleBufferSize = cSamples;
    15532075    }
    15542076    else
    15552077    {
    1556         AudioUnitUninitialize(pStreamIn->audioUnit);
    1557 
    1558         if (pStreamIn->pCircBuf)
    1559         {
    1560             RTCircBufDestroy(pStreamIn->pCircBuf);
    1561             pStreamIn->pCircBuf = NULL;
    1562         }
    1563 
    1564         coreAudioUninitConvCbCtx(&pStreamIn->convCbCtx);
    1565 
    1566         ASMAtomicXchgU32(&pStreamIn->status, CA_STATUS_UNINIT);
    1567     }
    1568 
    1569     LogFunc(("rc=%Rrc\n", rc));
     2078        int rc2 = coreAudioStreamUninit(pCAStream);
     2079        AssertRC(rc2);
     2080
     2081        ASMAtomicXchgU32(&pCAStream->status, COREAUDIOSTATUS_UNINIT);
     2082    }
     2083
     2084    LogFunc(("cSamples=%RU32, rc=%Rrc\n", cSamples, rc));
    15702085    return rc;
    15712086}
    15722087
    15732088/** @todo Eventually split up this function, as this already is huge! */
    1574 static int coreAudioInitOut(PDRVHOSTCOREAUDIO pThis,
    1575                             PPDMAUDIOSTREAM pStream, PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
    1576 {
    1577     RT_NOREF(pThis);
    1578 
     2089static int coreAudioStreamInitOut(PCOREAUDIOSTREAM pCAStream, PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
     2090{
    15792091    int rc = VINF_SUCCESS;
    1580 
    1581     PCOREAUDIOSTREAMOUT pStreamOut = (PCOREAUDIOSTREAMOUT)pStream;
    15822092    UInt32 cSamples = 0;
    15832093
    15842094    OSStatus err = noErr;
    1585     UInt32 uSize = 0;
    1586 
    1587     AudioDeviceID deviceID = pStreamOut->deviceID;
    1588     if (deviceID == kAudioDeviceUnknown)
    1589     {
    1590         /* Fetch the default audio recording device currently in use. */
    1591         AudioObjectPropertyAddress propAdr = { kAudioHardwarePropertyDefaultOutputDevice,
    1592                                                kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
    1593         uSize = sizeof(deviceID);
    1594         err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &propAdr, 0, NULL, &uSize, &deviceID);
    1595         if (err != noErr)
    1596         {
    1597             LogRel(("CoreAudio: Unable to determine default playback device (%RI32)\n", err));
    1598             return VERR_NOT_FOUND;
    1599         }
    1600     }
    1601 
    1602     if (deviceID == kAudioDeviceUnknown)
    1603     {
    1604         LogFlowFunc(("No default playback device found\n"));
    1605         return VERR_NOT_FOUND;
    1606     }
     2095
     2096    PPDMAUDIODEVICE pDev = pCAStream->Unit.pDevice;
     2097    AssertPtr(pDev);
     2098
     2099    PCOREAUDIODEVICEDATA pData = (PCOREAUDIODEVICEDATA)pDev->pvData;
     2100    AssertPtr(pData);
     2101
     2102    AudioDeviceID deviceID = pData->deviceID;
     2103    Assert(deviceID != kAudioDeviceUnknown);
    16072104
    16082105    do
    16092106    {
    1610         ASMAtomicXchgU32(&pStreamOut->status, CA_STATUS_IN_INIT);
    1611 
    1612         /* Assign device ID. */
    1613         pStreamOut->deviceID = deviceID;
    1614 
    1615         /*
    1616          * Try to get the name of the playback device and log it. It's not fatal if it fails.
    1617          */
    1618         CFStringRef strTemp;
    1619 
    1620         AudioObjectPropertyAddress propAdr = { kAudioObjectPropertyName, kAudioObjectPropertyScopeGlobal,
    1621                                                kAudioObjectPropertyElementMaster };
    1622         uSize = sizeof(CFStringRef);
    1623         err = AudioObjectGetPropertyData(pStreamOut->deviceID, &propAdr, 0, NULL, &uSize, &strTemp);
    1624         if (err == noErr)
    1625         {
    1626             char *pszDevName = NULL;
    1627             err = coreAudioCFStringToCString(strTemp, &pszDevName);
    1628             if (err == noErr)
    1629             {
    1630                 CFRelease(strTemp);
    1631 
    1632                 /* Get the device' UUID. */
    1633                 propAdr.mSelector = kAudioDevicePropertyDeviceUID;
    1634                 err = AudioObjectGetPropertyData(pStreamOut->deviceID, &propAdr, 0, NULL, &uSize, &strTemp);
    1635                 if (err == noErr)
    1636                 {
    1637                     char *pszUID = NULL;
    1638                     err = coreAudioCFStringToCString(strTemp, &pszUID);
    1639                     if (err == noErr)
    1640                     {
    1641                         CFRelease(strTemp);
    1642                         LogRel(("CoreAudio: Using playback device: %s (UID: %s)\n", pszDevName, pszUID));
    1643 
    1644                         RTMemFree(pszUID);
    1645                     }
    1646                 }
    1647 
    1648                 RTMemFree(pszDevName);
    1649             }
    1650         }
    1651         else
    1652             LogRel(("CoreAudio: Unable to determine playback device name (%RI32)\n", err));
     2107        ASMAtomicXchgU32(&pCAStream->status, COREAUDIOSTATUS_IN_INIT);
    16532108
    16542109        /* Get the default frames buffer size, so that we can setup our internal buffers. */
    16552110        UInt32 cFrames;
    1656         uSize = sizeof(cFrames);
     2111        UInt32 uSize = sizeof(cFrames);
     2112
     2113        AudioObjectPropertyAddress propAdr;
    16572114        propAdr.mSelector = kAudioDevicePropertyBufferFrameSize;
    16582115        propAdr.mScope    = kAudioDevicePropertyScopeInput;
    1659         err = AudioObjectGetPropertyData(pStreamOut->deviceID, &propAdr, 0, NULL, &uSize, &cFrames);
     2116        propAdr.mElement  = kAudioObjectPropertyElementMaster;
     2117        err = AudioObjectGetPropertyData(deviceID, &propAdr, 0, NULL, &uSize, &cFrames);
    16602118        if (err != noErr)
    16612119        {
     
    16652123
    16662124        /* Set the frame buffer size and honor any minimum/maximum restrictions on the device. */
    1667         err = coreAudioSetFrameBufferSize(pStreamOut->deviceID, false /* fInput */, cFrames, &cFrames);
     2125        err = coreAudioSetFrameBufferSize(deviceID, false /* fInput */, cFrames, &cFrames);
    16682126        if (err != noErr)
    16692127        {
     
    16882146
    16892147        /* Open the default HAL output component. */
    1690         err = AudioComponentInstanceNew(cp, &pStreamOut->audioUnit);
     2148        err = AudioComponentInstanceNew(cp, &pCAStream->Unit.audioUnit);
    16912149        if (err != noErr)
    16922150        {
     
    16972155        /* Switch the I/O mode for output to on. */
    16982156        UInt32 uFlag = 1;
    1699         err = AudioUnitSetProperty(pStreamOut->audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output,
     2157        err = AudioUnitSetProperty(pCAStream->Unit.audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output,
    17002158                                   0, &uFlag, sizeof(uFlag));
    17012159        if (err != noErr)
     
    17062164
    17072165        /* Set the default audio playback device as the device for the new AudioUnit. */
    1708         err = AudioUnitSetProperty(pStreamOut->audioUnit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global,
    1709                                    0, &pStreamOut->deviceID, sizeof(pStreamOut->deviceID));
     2166        err = AudioUnitSetProperty(pCAStream->Unit.audioUnit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global,
     2167                                   0, &deviceID, sizeof(deviceID));
    17102168        if (err != noErr)
    17112169        {
     
    17202178        AURenderCallbackStruct cb;
    17212179        RT_ZERO(cb);
    1722         cb.inputProc       = coreAudioPlaybackCb; /* pvUser */
    1723         cb.inputProcRefCon = pStreamOut;
    1724 
    1725         err = AudioUnitSetProperty(pStreamOut->audioUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input,
     2180        cb.inputProc       = coreAudioPlaybackCb;
     2181        cb.inputProcRefCon = pCAStream; /* pvUser */
     2182
     2183        err = AudioUnitSetProperty(pCAStream->Unit.audioUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input,
    17262184                                   0, &cb, sizeof(cb));
    17272185        if (err != noErr)
    17282186        {
    1729             LogRel(("CoreAudio: Failed to register output callback (%RI32)\n", err));
     2187            LogRel(("CoreAudio: Failed to register playback callback (%RI32)\n", err));
    17302188            CA_BREAK_STMT(rc = VERR_AUDIO_BACKEND_INIT_FAILED);
    17312189        }
    17322190
    1733         /* Fetch the current stream format of the device. */
    1734         uSize = sizeof(pStreamOut->deviceFormat);
    1735         err = AudioUnitGetProperty(pStreamOut->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input,
    1736                                    0, &pStreamOut->deviceFormat, &uSize);
     2191        AudioStreamBasicDescription reqFmt;
     2192        coreAudioStreamCfgToASBD(pCfgReq, &reqFmt);
     2193        coreAudioPrintASBD("Requested stream output format", &reqFmt);
     2194
     2195        /* Fetch the initial input format of the device. */
     2196        AudioStreamBasicDescription devInFmt;
     2197        uSize = sizeof(devInFmt);
     2198        err = AudioUnitGetProperty(pCAStream->Unit.audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input,
     2199                                   0, &devInFmt, &uSize);
    17372200        if (err != noErr)
    17382201        {
    1739             LogRel(("CoreAudio: Failed to get device format (%RI32)\n", err));
     2202            LogRel(("CoreAudio: Failed to get input format of playback device (%RI32)\n", err));
    17402203            CA_BREAK_STMT(rc = VERR_AUDIO_BACKEND_INIT_FAILED);
    17412204        }
    17422205
    1743         /* Create an AudioStreamBasicDescription based on our required audio settings. */
    1744         coreAudioStreamCfgToASBD(pCfgReq, &pStreamOut->streamFormat);
    1745 
    1746         coreAudioPrintASBD("Playback device", &pStreamOut->deviceFormat);
    1747         coreAudioPrintASBD("Playback format", &pStreamOut->streamFormat);
    1748 
    1749         /* Set the new output format description for the stream. */
    1750         err = AudioUnitSetProperty(pStreamOut->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input,
    1751                                    0, &pStreamOut->streamFormat, sizeof(pStreamOut->streamFormat));
     2206        coreAudioPrintASBD("Output device in (initial)", &devInFmt);
     2207
     2208        /* Fetch the initial output format of the device. */
     2209        AudioStreamBasicDescription devOutFmt;
     2210        uSize = sizeof(devOutFmt);
     2211        err = AudioUnitGetProperty(pCAStream->Unit.audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output,
     2212                                   0, &devOutFmt, &uSize);
    17522213        if (err != noErr)
    17532214        {
     2215            LogRel(("CoreAudio: Failed to get output format of playback device (%RI32)\n", err));
     2216            CA_BREAK_STMT(rc = VERR_AUDIO_BACKEND_INIT_FAILED);
     2217        }
     2218
     2219        coreAudioPrintASBD("Output device out (initial)", &devOutFmt);
     2220
     2221        /* Set the new input format for the output device. */
     2222        err = AudioUnitSetProperty(pCAStream->Unit.audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input,
     2223                                   0, &reqFmt, sizeof(reqFmt));
     2224        if (err != noErr)
     2225        {
    17542226            LogRel(("CoreAudio: Failed to set stream format for output stream (%RI32)\n", err));
    1755             CA_BREAK_STMT(rc = VERR_AUDIO_BACKEND_INIT_FAILED);
    1756         }
    1757 
    1758         uSize = sizeof(pStreamOut->deviceFormat);
    1759         err = AudioUnitGetProperty(pStreamOut->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input,
    1760                                    0, &pStreamOut->deviceFormat, &uSize);
    1761         if (err != noErr)
    1762         {
    1763             LogRel(("CoreAudio: Failed to retrieve device format for output stream (%RI32)\n", err));
    17642227            CA_BREAK_STMT(rc = VERR_AUDIO_BACKEND_INIT_FAILED);
    17652228        }
     
    17702233         * thread is as we like.
    17712234         */
    1772         err = AudioUnitSetProperty(pStreamOut->audioUnit, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global,
     2235        err = AudioUnitSetProperty(pCAStream->Unit.audioUnit, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global,
    17732236                                   0, &cFrames, sizeof(cFrames));
    17742237        if (err != noErr)
     
    17782241        }
    17792242
    1780         /* Finally initialize the new AudioUnit. */
    1781         err = AudioUnitInitialize(pStreamOut->audioUnit);
     2243        /*
     2244         * Initialize the new AudioUnit.
     2245         */
     2246        err = AudioUnitInitialize(pCAStream->Unit.audioUnit);
    17822247        if (err != noErr)
    17832248        {
     
    17852250            CA_BREAK_STMT(rc = VERR_AUDIO_BACKEND_INIT_FAILED);
    17862251        }
     2252
     2253        /* Fetch the final output format of the device after the audio unit has been initialized. */
     2254        uSize = sizeof(devInFmt);
     2255        err = AudioUnitGetProperty(pCAStream->Unit.audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input,
     2256                                   0, &devInFmt, &uSize);
     2257        if (err != noErr)
     2258        {
     2259            LogRel(("CoreAudio: Failed re-getting input format of output device (%RI32)\n", err));
     2260            CA_BREAK_STMT(rc = VERR_AUDIO_BACKEND_INIT_FAILED);
     2261        }
     2262
     2263        coreAudioPrintASBD("Output device in (after initialization)", &devInFmt);
     2264
     2265        /* Save this final output format as our stream format. */
     2266        memcpy(&pCAStream->Unit.streamFmt, &devInFmt, sizeof(AudioStreamBasicDescription));
    17872267
    17882268        /*
     
    17922272         */
    17932273        uSize = sizeof(cFrames);
    1794         err = AudioUnitGetProperty(pStreamOut->audioUnit, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global,
     2274        err = AudioUnitGetProperty(pCAStream->Unit.audioUnit, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global,
    17952275                                   0, &cFrames, &uSize);
    17962276        if (err != noErr)
    17972277        {
    17982278            LogRel(("CoreAudio: Failed to get maximum frame buffer size from output audio device (%RI32)\n", err));
    1799 
    1800             AudioUnitUninitialize(pStreamOut->audioUnit);
    18012279            CA_BREAK_STMT(rc = VERR_AUDIO_BACKEND_INIT_FAILED);
    18022280        }
     
    18092287         * samples count.
    18102288         */
    1811         cSamples = cFrames * pStreamOut->streamFormat.mChannelsPerFrame;
     2289        cSamples = cFrames * reqFmt.mChannelsPerFrame;
    18122290        if (!cSamples)
    18132291        {
     
    18162294        }
    18172295
    1818         /* Destroy any former internal ring buffer. */
    1819         if (pStreamOut->pCircBuf)
    1820         {
    1821             RTCircBufDestroy(pStreamOut->pCircBuf);
    1822             pStreamOut->pCircBuf = NULL;
    1823         }
    1824 
    1825         PDMAUDIOPCMPROPS PCMProps;
    1826         int rc2 = DrvAudioHlpStreamCfgToProps(pCfgAcq, &PCMProps);
     2296        /* Create the internal ring buffer. */
     2297        rc = RTCircBufCreate(&pCAStream->pCircBuf, cSamples << 1 /*pHstStrmOut->Props.cShift*/); /** @todo FIX THIS !!! */
     2298
     2299    } while (0);
     2300
     2301    if (RT_SUCCESS(rc))
     2302    {
     2303        pCAStream->enmDir = PDMAUDIODIR_OUT;
     2304
     2305        rc = coreAudioASBDToStreamCfg(&pCAStream->Unit.streamFmt, pCfgAcq);
     2306        AssertRC(rc);
     2307
     2308        ASMAtomicXchgU32(&pCAStream->status, COREAUDIOSTATUS_INIT);
     2309
     2310        pCfgAcq->cSampleBufferSize = cSamples;
     2311    }
     2312    else
     2313    {
     2314        int rc2 = coreAudioStreamUninit(pCAStream);
    18272315        AssertRC(rc2);
    18282316
    1829         rc = RTCircBufCreate(&pStreamOut->pCircBuf, cSamples << PCMProps.cShift);
    1830         if (RT_FAILURE(rc))
    1831             break;
    1832 
     2317        ASMAtomicXchgU32(&pCAStream->status, COREAUDIOSTATUS_UNINIT);
     2318    }
     2319
     2320    LogFunc(("cSamples=%RU32, rc=%Rrc\n", cSamples, rc));
     2321    return rc;
     2322}
     2323
     2324
     2325/**
     2326 * Uninitializes a Core Audio stream.
     2327 *
     2328 * @return IPRT status code.
     2329 * @param  pCAStream            Stream to uninitialize.
     2330 */
     2331static int coreAudioStreamUninit(PCOREAUDIOSTREAM pCAStream)
     2332{
     2333    OSStatus err = noErr;
     2334
     2335    if (pCAStream->Unit.audioUnit)
     2336    {
     2337        err = AudioUnitUninitialize(pCAStream->Unit.audioUnit);
     2338        if (err == noErr)
     2339        {
     2340            err = AudioComponentInstanceDispose(pCAStream->Unit.audioUnit);
     2341            if (err == noErr)
     2342                pCAStream->Unit.audioUnit = NULL;
     2343        }
     2344    }
     2345
     2346    if (err == noErr)
     2347    {
     2348        if (pCAStream->pCircBuf)
     2349        {
     2350            RTCircBufDestroy(pCAStream->pCircBuf);
     2351            pCAStream->pCircBuf = NULL;
     2352        }
     2353
     2354        pCAStream->status = COREAUDIOSTATUS_UNINIT;
     2355
     2356        pCAStream->enmDir = PDMAUDIODIR_UNKNOWN;
     2357        pCAStream->pDrv   = NULL;
     2358
     2359        pCAStream->Unit.pDevice = NULL;
     2360        RT_ZERO(pCAStream->Unit.streamFmt);
     2361
     2362        if (pCAStream->enmDir == PDMAUDIODIR_IN)
     2363        {
     2364#ifdef VBOX_WITH_AUDIO_CA_CONVERTER
     2365            if (pCAStream->In.ConverterRef)
     2366            {
     2367                AudioConverterDispose(pCAStream->In.ConverterRef);
     2368                pCAStream->In.ConverterRef = NULL;
     2369            }
     2370
     2371            drvHostCoreAudioUninitConvCbCtx(&pCAStream->In.convCbCtx);
     2372#endif
     2373            pCAStream->In.sampleRatio = 1;
     2374        }
     2375        else if (pCAStream->enmDir == PDMAUDIODIR_OUT)
     2376        {
     2377
     2378        }
     2379    }
     2380    else
     2381        LogRel(("CoreAudio: Failed to uninit stream (%RI32)\n", err));
     2382
     2383    return err == noErr ? VINF_SUCCESS : VERR_GENERAL_FAILURE; /** @todo Fudge! */
     2384}
     2385
     2386
     2387/**
     2388 * Registers callbacks for a specific Core Audio device.
     2389 *
     2390 * @return IPRT status code.
     2391 * @param  pThis                Host audio driver instance.
     2392 * @param  pDev                 Audio device to use for the registered callbacks.
     2393 */
     2394static int coreAudioDeviceRegisterCallbacks(PDRVHOSTCOREAUDIO pThis, PPDMAUDIODEVICE pDev)
     2395{
     2396    RT_NOREF(pThis);
     2397
     2398    AudioDeviceID deviceID = kAudioDeviceUnknown;
     2399
     2400    PCOREAUDIODEVICEDATA pData = (PCOREAUDIODEVICEDATA)pDev->pvData;
     2401    if (pData)
     2402        deviceID = pData->deviceID;
     2403
     2404    if (deviceID != kAudioDeviceUnknown)
     2405    {
    18332406        /*
    1834          * Register callbacks.
     2407         * Register device callbacks.
    18352408         */
    1836 #ifdef DEBUG
     2409        AudioObjectPropertyAddress propAdr = { kAudioDevicePropertyDeviceIsAlive, kAudioObjectPropertyScopeGlobal,
     2410                                               kAudioObjectPropertyElementMaster };
     2411        OSStatus err = AudioObjectAddPropertyListener(deviceID, &propAdr,
     2412                                                      coreAudioDeviceStateChangedCb, pDev /* pvUser */);
     2413        if (   err != noErr
     2414            && err != kAudioHardwareIllegalOperationError)
     2415        {
     2416            LogRel(("CoreAudio: Failed to add the recording device state changed listener (%RI32)\n", err));
     2417        }
     2418
    18372419        propAdr.mSelector = kAudioDeviceProcessorOverload;
    18382420        propAdr.mScope    = kAudioUnitScope_Global;
    1839         err = AudioObjectAddPropertyListener(pStreamOut->deviceID, &propAdr,
    1840                                              coreAudioPlaybackAudioDevicePropertyChanged, (void *)pStreamOut);
     2421        err = AudioObjectAddPropertyListener(deviceID, &propAdr,
     2422                                             coreAudioDevPropChgCb, pDev /* pvUser */);
    18412423        if (err != noErr)
    1842             LogRel(("CoreAudio: Failed to register processor overload listener for output stream (%RI32)\n", err));
    1843 #endif /* DEBUG */
     2424            LogRel(("CoreAudio: Failed to register processor overload listener (%RI32)\n", err));
    18442425
    18452426        propAdr.mSelector = kAudioDevicePropertyNominalSampleRate;
    18462427        propAdr.mScope    = kAudioUnitScope_Global;
    1847         err = AudioObjectAddPropertyListener(pStreamOut->deviceID, &propAdr,
    1848                                              coreAudioPlaybackAudioDevicePropertyChanged, (void *)pStreamOut);
    1849         /* Not fatal. */
     2428        err = AudioObjectAddPropertyListener(deviceID, &propAdr,
     2429                                             coreAudioDevPropChgCb, pDev /* pvUser */);
    18502430        if (err != noErr)
    1851             LogRel(("CoreAudio: Failed to register sample rate changed listener for output stream (%RI32)\n", err));
    1852 
    1853     } while (0);
    1854 
    1855     if (RT_SUCCESS(rc))
    1856     {
    1857         ASMAtomicXchgU32(&pStreamOut->status, CA_STATUS_INIT);
    1858 
    1859         LogFunc(("cSamples=%RU32\n", cSamples));
    1860 
    1861         if (pCfgAcq)
    1862             pCfgAcq->cSampleBufferSize = cSamples;
    1863     }
    1864     else
    1865     {
    1866         AudioUnitUninitialize(pStreamOut->audioUnit);
    1867 
    1868         if (pStreamOut->pCircBuf)
    1869         {
    1870             RTCircBufDestroy(pStreamOut->pCircBuf);
    1871             pStreamOut->pCircBuf = NULL;
    1872         }
    1873 
    1874         ASMAtomicXchgU32(&pStreamOut->status, CA_STATUS_UNINIT);
    1875     }
    1876 
    1877     LogFunc(("cSamples=%RU32, rc=%Rrc\n", cSamples, rc));
    1878     return rc;
    1879 }
    1880 
    1881 
    1882 /**
    1883  * Implements the OS X callback AudioObjectPropertyListenerProc for getting
    1884  * notified when some of the properties of an audio device has changed.
    1885  */
    1886 static OSStatus coreAudioPlaybackAudioDevicePropertyChanged(AudioObjectID propertyID,
    1887                                                             UInt32 cAddresses,
    1888                                                             const AudioObjectPropertyAddress paProperties[],
    1889                                                             void *pvUser)
    1890 {
    1891     RT_NOREF(propertyID, cAddresses, paProperties, pvUser)
     2431            LogRel(("CoreAudio: Failed to register sample rate changed listener (%RI32)\n", err));
     2432    }
     2433
     2434    return VINF_SUCCESS;
     2435}
     2436
     2437/**
     2438 * Unregisters all formerly registered callbacks of a Core Audio device again.
     2439 *
     2440 * @return IPRT status code.
     2441 * @param  pThis                Host audio driver instance.
     2442 * @param  pDev                 Audio device to use for the registered callbacks.
     2443 */
     2444static int coreAudioDeviceUnregisterCallbacks(PDRVHOSTCOREAUDIO pThis, PPDMAUDIODEVICE pDev)
     2445{
     2446    RT_NOREF(pThis);
     2447
     2448    AudioDeviceID deviceID = kAudioDeviceUnknown;
     2449
     2450    if (pDev)
     2451    {
     2452        PCOREAUDIODEVICEDATA pData = (PCOREAUDIODEVICEDATA)pDev->pvData;
     2453        if (pData)
     2454            deviceID = pData->deviceID;
     2455    }
     2456
     2457    if (deviceID != kAudioDeviceUnknown)
     2458    {
     2459        /*
     2460         * Unregister per-device callbacks.
     2461         */
     2462        AudioObjectPropertyAddress propAdr = { kAudioDeviceProcessorOverload, kAudioObjectPropertyScopeGlobal,
     2463                                               kAudioObjectPropertyElementMaster };
     2464        OSStatus err = AudioObjectRemovePropertyListener(deviceID, &propAdr,
     2465                                                         coreAudioDevPropChgCb, pDev /* pvUser */);
     2466        if (   err != noErr
     2467            && err != kAudioHardwareBadObjectError)
     2468        {
     2469            LogRel(("CoreAudio: Failed to remove the recording processor overload listener (%RI32)\n", err));
     2470        }
     2471
     2472        propAdr.mSelector = kAudioDevicePropertyNominalSampleRate;
     2473        err = AudioObjectRemovePropertyListener(deviceID, &propAdr,
     2474                                                coreAudioDevPropChgCb, pDev /* pvUser */);
     2475        if (   err != noErr
     2476            && err != kAudioHardwareBadObjectError)
     2477        {
     2478            LogRel(("CoreAudio: Failed to remove the sample rate changed listener (%RI32)\n", err));
     2479        }
     2480
     2481        propAdr.mSelector = kAudioDevicePropertyDeviceIsAlive;
     2482        err = AudioObjectRemovePropertyListener(deviceID, &propAdr,
     2483                                                coreAudioDeviceStateChangedCb, pDev /* pvUser */);
     2484        if (   err != noErr
     2485            && err != kAudioHardwareBadObjectError)
     2486        {
     2487            LogRel(("CoreAudio: Failed to remove the device alive listener (%RI32)\n", err));
     2488        }
     2489    }
     2490
     2491    return VINF_SUCCESS;
     2492}
     2493
     2494/* Callback for getting notified when some of the properties of an audio device have changed. */
     2495static DECLCALLBACK(OSStatus) coreAudioDevPropChgCb(AudioObjectID                     propertyID,
     2496                                                    UInt32                            cAddresses,
     2497                                                    const AudioObjectPropertyAddress  properties[],
     2498                                                    void                             *pvUser)
     2499{
     2500    RT_NOREF(cAddresses, properties);
     2501
     2502    PPDMAUDIODEVICE pDev = (PPDMAUDIODEVICE)pvUser;
     2503    AssertPtr(pDev);
     2504
     2505    LogFlowFunc(("propertyID=%u, nAddresses=%u, pDev=%p\n", propertyID, cAddresses, pDev));
    18922506
    18932507    switch (propertyID)
    18942508    {
    18952509#ifdef DEBUG
     2510       case kAudioDeviceProcessorOverload:
     2511        {
     2512            LogFunc(("Processor overload detected!\n"));
     2513            break;
     2514        }
    18962515#endif /* DEBUG */
     2516        case kAudioDevicePropertyNominalSampleRate:
     2517        {
     2518            int rc2 = coreAudioDevicePropagateStatus(pDev, COREAUDIOSTATUS_REINIT);
     2519            AssertRC(rc2);
     2520            break;
     2521        }
     2522
    18972523        default:
     2524            /* Just skip. */
    18982525            break;
    18992526    }
     
    19022529}
    19032530
    1904 
    1905 /**
    1906  * Implements the OS X callback AURenderCallback in order to feed the audio
    1907  * output buffer.
    1908  */
    1909 static OSStatus coreAudioPlaybackCb(void *pvUser,
    1910                                     AudioUnitRenderActionFlags *pActionFlags,
    1911                                     const AudioTimeStamp       *pAudioTS,
    1912                                     UInt32                      uBusID,
    1913                                     UInt32                      cFrames,
    1914                                     AudioBufferList            *pBufData)
     2531/* Callback to feed audio output buffer. */
     2532static DECLCALLBACK(OSStatus) coreAudioPlaybackCb(void                       *pvUser,
     2533                                                  AudioUnitRenderActionFlags *pActionFlags,
     2534                                                  const AudioTimeStamp       *pAudioTS,
     2535                                                  UInt32                      uBusID,
     2536                                                  UInt32                      cFrames,
     2537                                                  AudioBufferList            *pBufData)
    19152538{
    19162539    RT_NOREF(pActionFlags, pAudioTS, uBusID, cFrames);
    1917     PCOREAUDIOSTREAMOUT pStreamOut  = (PCOREAUDIOSTREAMOUT)pvUser;
    1918 
    1919     if (ASMAtomicReadU32(&pStreamOut->status) != CA_STATUS_INIT)
     2540
     2541    PCOREAUDIOSTREAM pStream = (PCOREAUDIOSTREAM)pvUser;
     2542
     2543    /* Sanity. */
     2544    AssertPtr(pStream);
     2545    AssertPtr(pStream->pDrv);
     2546    Assert   (pStream->enmDir == PDMAUDIODIR_OUT);
     2547    AssertPtr(pStream->Unit.pDevice);
     2548
     2549    if (ASMAtomicReadU32(&pStream->status) != COREAUDIOSTATUS_INIT)
    19202550    {
    19212551        pBufData->mBuffers[0].mDataByteSize = 0;
     
    19242554
    19252555    /* How much space is used in the ring buffer? */
    1926     size_t cbToRead = RT_MIN(RTCircBufUsed(pStreamOut->pCircBuf), pBufData->mBuffers[0].mDataByteSize);
     2556    size_t cbToRead = RT_MIN(RTCircBufUsed(pStream->pCircBuf), pBufData->mBuffers[0].mDataByteSize);
    19272557    if (!cbToRead)
    19282558    {
     
    19382568    {
    19392569        /* Try to acquire the necessary block from the ring buffer. */
    1940         RTCircBufAcquireReadBlock(pStreamOut->pCircBuf, cbLeft, (void **)&pbSrc, &cbToRead);
     2570        RTCircBufAcquireReadBlock(pStream->pCircBuf, cbLeft, (void **)&pbSrc, &cbToRead);
    19412571
    19422572        /* Break if nothing is used anymore. */
     
    19482578
    19492579        /* Release the read buffer, so it could be used for new data. */
    1950         RTCircBufReleaseReadBlock(pStreamOut->pCircBuf, cbToRead);
     2580        RTCircBufReleaseReadBlock(pStream->pCircBuf, cbToRead);
    19512581
    19522582        /* Move offset. */
     
    19762606
    19772607/**
    1978  * @interface_method_impl{PDMIHOSTAUDIO, pfnInit}
    1979  *
    1980  * @todo Please put me next to the shutdown function, because then it would be
    1981  *       clear why I'm empty.  While at it, it would be nice if you also
    1982  *       reordered my PDMIHOSTAUDIO sibilings according to the interface
    1983  *       (doesn't matter if it's reversed (like all other PDM drivers and
    1984  *       devices) or not).
    1985  */
    1986 static DECLCALLBACK(int) drvHostCoreAudioInit(PPDMIHOSTAUDIO pInterface)
    1987 {
    1988     RT_NOREF(pInterface);
    1989 
    1990     LogFlowFuncEnter();
    1991 
    1992     return VINF_SUCCESS;
    1993 }
    1994 
    1995 /**
    19962608 * @interface_method_impl{PDMIHOSTAUDIO, pfnStreamCapture}
    19972609 */
     
    20052617    /* pcbRead is optional. */
    20062618
    2007     PCOREAUDIOSTREAMIN pStreamIn = (PCOREAUDIOSTREAMIN)pStream;
    2008 
    2009 /* unused, make you wonder why...
    2010     size_t csReads = 0;
    2011     char *pcSrc;
    2012     PPDMAUDIOSAMPLE psDst; */
    2013 
    2014     if (ASMAtomicReadU32(&pStreamIn->status) != CA_STATUS_INIT)
     2619    PDRVHOSTCOREAUDIO pThis     = PDMIHOSTAUDIO_2_DRVHOSTCOREAUDIO(pInterface);
     2620    PCOREAUDIOSTREAM  pCAStream = (PCOREAUDIOSTREAM)pStream;
     2621
     2622    /* Check if the audio device should be reinitialized. If so do it. */
     2623    if (ASMAtomicReadU32(&pCAStream->status) == COREAUDIOSTATUS_REINIT)
     2624    {
     2625        /* For now re just re-initialize with the current input device. */
     2626        if (pThis->pDefaultDevIn)
     2627        {
     2628            int rc2 = coreAudioStreamReinit(pThis, pCAStream, pThis->pDefaultDevIn);
     2629            if (RT_FAILURE(rc2))
     2630                return VERR_NOT_AVAILABLE;
     2631        }
     2632        else
     2633            return VERR_NOT_AVAILABLE;
     2634    }
     2635
     2636    if (ASMAtomicReadU32(&pCAStream->status) != COREAUDIOSTATUS_INIT)
    20152637    {
    20162638        if (pcbRead)
     
    20252647    {
    20262648        size_t cbMixBuf  = AudioMixBufSizeBytes(&pStream->MixBuf);
    2027         size_t cbToWrite = RT_MIN(cbMixBuf, RTCircBufUsed(pStreamIn->pCircBuf));
     2649        size_t cbToWrite = RT_MIN(cbMixBuf, RTCircBufUsed(pCAStream->pCircBuf));
    20282650
    20292651        uint32_t cWritten, cbWritten;
     
    20312653        size_t   cbToRead;
    20322654
    2033         Log3Func(("cbMixBuf=%zu, cbToWrite=%zu/%zu\n", cbMixBuf, cbToWrite, RTCircBufSize(pStreamIn->pCircBuf)));
     2655        Log3Func(("cbMixBuf=%zu, cbToWrite=%zu/%zu\n", cbMixBuf, cbToWrite, RTCircBufSize(pCAStream->pCircBuf)));
    20342656
    20352657        while (cbToWrite)
    20362658        {
    20372659            /* Try to acquire the necessary block from the ring buffer. */
    2038             RTCircBufAcquireReadBlock(pStreamIn->pCircBuf, cbToWrite, (void **)&puBuf, &cbToRead);
     2660            RTCircBufAcquireReadBlock(pCAStream->pCircBuf, cbToWrite, (void **)&puBuf, &cbToRead);
    20392661            if (!cbToRead)
    20402662            {
    2041                 RTCircBufReleaseReadBlock(pStreamIn->pCircBuf, cbToRead);
     2663                RTCircBufReleaseReadBlock(pCAStream->pCircBuf, cbToRead);
    20422664                break;
    20432665            }
     
    20552677                AssertFailed();
    20562678#endif
    2057             rc = AudioMixBufWriteCirc(&pStream->MixBuf, puBuf, cbToRead, &cWritten);
     2679            rc = AudioMixBufWriteCirc(&pStream->MixBuf, puBuf + cbWrittenTotal, cbToRead, &cWritten);
    20582680
    20592681            /* Release the read buffer, so it could be used for new data. */
    2060             RTCircBufReleaseReadBlock(pStreamIn->pCircBuf, cbToRead);
     2682            RTCircBufReleaseReadBlock(pCAStream->pCircBuf, cbToRead);
    20612683
    20622684            if (   RT_FAILURE(rc)
    20632685                || !cWritten)
    20642686            {
    2065                 RTCircBufReleaseReadBlock(pStreamIn->pCircBuf, cbToRead);
     2687                RTCircBufReleaseReadBlock(pCAStream->pCircBuf, cbToRead);
    20662688                break;
    20672689            }
    20682690
    20692691            cbWritten = AUDIOMIXBUF_S2B(&pStream->MixBuf, cWritten);
    2070 
    2071             /* Release the read buffer, so it could be used for new data. */
    2072             RTCircBufReleaseReadBlock(pStreamIn->pCircBuf, cbWritten);
    20732692
    20742693            Assert(cbToWrite >= cbWritten);
     
    21072726 */
    21082727static DECLCALLBACK(int) drvHostCoreAudioStreamPlay(PPDMIHOSTAUDIO pInterface,
    2109                                                     PPDMAUDIOSTREAM pStream,
    2110                                                     const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten)
    2111 {
    2112     RT_NOREF(pvBuf, cbBuf); /** @todo r=bird: this looks weird at first glance... */
    2113 
    2114     AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
    2115     AssertPtrReturn(pStream,    VERR_INVALID_POINTER);
    2116     /* pcbWritten is optional. */
    2117 
    2118     PCOREAUDIOSTREAMOUT pStreamOut = (PCOREAUDIOSTREAMOUT)pStream;
    2119 
    2120     int rc = VINF_SUCCESS;
     2728                                                    PPDMAUDIOSTREAM pStream, const void *pvBuf, uint32_t cbBuf,
     2729                                                    uint32_t *pcbWritten)
     2730{
     2731    RT_NOREF(pvBuf, cbBuf);
     2732
     2733    PDRVHOSTCOREAUDIO pThis     = PDMIHOSTAUDIO_2_DRVHOSTCOREAUDIO(pInterface);
     2734    PCOREAUDIOSTREAM  pCAStream = (PCOREAUDIOSTREAM)pStream;
     2735
     2736    /* Check if the audio device should be reinitialized. If so do it. */
     2737    if (ASMAtomicReadU32(&pCAStream->status) == COREAUDIOSTATUS_REINIT)
     2738    {
     2739        if (pThis->pDefaultDevOut)
     2740        {
     2741            /* For now re just re-initialize with the current output device. */
     2742            int rc2 = coreAudioStreamReinit(pThis, pCAStream, pThis->pDefaultDevOut);
     2743            if (RT_FAILURE(rc2))
     2744                return VERR_NOT_AVAILABLE;
     2745        }
     2746        else
     2747            return VERR_NOT_AVAILABLE;
     2748    }
    21212749
    21222750    uint32_t cLive = AudioMixBufLive(&pStream->MixBuf);
     
    21322760    uint32_t cbReadTotal = 0;
    21332761
    2134     size_t cbToRead = RT_MIN(cbLive, RTCircBufFree(pStreamOut->pCircBuf));
     2762    size_t cbToRead = RT_MIN(cbLive, RTCircBufFree(pCAStream->pCircBuf));
    21352763    Log3Func(("cbToRead=%zu\n", cbToRead));
     2764
     2765    int rc = VINF_SUCCESS;
    21362766
    21372767    while (cbToRead)
     
    21422772
    21432773        /* Try to acquire the necessary space from the ring buffer. */
    2144         RTCircBufAcquireWriteBlock(pStreamOut->pCircBuf, cbToRead, (void **)&puBuf, &cbCopy);
     2774        RTCircBufAcquireWriteBlock(pCAStream->pCircBuf, cbToRead, (void **)&puBuf, &cbCopy);
    21452775        if (!cbCopy)
    21462776        {
    2147             RTCircBufReleaseWriteBlock(pStreamOut->pCircBuf, cbCopy);
     2777            RTCircBufReleaseWriteBlock(pCAStream->pCircBuf, cbCopy);
    21482778            break;
    21492779        }
     
    21512781        Assert(cbCopy <= cbToRead);
    21522782
    2153         rc = AudioMixBufReadCirc(&pStream->MixBuf,
    2154                                  puBuf, cbCopy, &cRead);
    2155 
     2783        rc = AudioMixBufReadCirc(&pStream->MixBuf, puBuf, cbCopy, &cRead);
    21562784        if (   RT_FAILURE(rc)
    21572785            || !cRead)
    21582786        {
    2159             RTCircBufReleaseWriteBlock(pStreamOut->pCircBuf, 0);
     2787            RTCircBufReleaseWriteBlock(pCAStream->pCircBuf, 0);
    21602788            break;
    21612789        }
     
    21642792
    21652793        /* Release the ring buffer, so the read thread could start reading this data. */
    2166         RTCircBufReleaseWriteBlock(pStreamOut->pCircBuf, cbRead);
     2794        RTCircBufReleaseWriteBlock(pCAStream->pCircBuf, cbRead);
    21672795
    21682796        Assert(cbToRead >= cbRead);
     
    21862814}
    21872815
    2188 static int coreAudioControlStreamOut(PPDMAUDIOSTREAM pStream, PDMAUDIOSTREAMCMD enmStreamCmd)
    2189 {
    2190     PCOREAUDIOSTREAMOUT pStreamOut = (PCOREAUDIOSTREAMOUT)pStream;
     2816static DECLCALLBACK(int) coreAudioStreamControl(PDRVHOSTCOREAUDIO pThis,
     2817                                                PCOREAUDIOSTREAM pCAStream, PDMAUDIOSTREAMCMD enmStreamCmd)
     2818{
     2819    RT_NOREF(pThis);
    21912820
    21922821    LogFlowFunc(("enmStreamCmd=%RU32\n", enmStreamCmd));
    21932822
    2194     uint32_t uStatus = ASMAtomicReadU32(&pStreamOut->status);
    2195     if (!(   uStatus == CA_STATUS_INIT
    2196           || uStatus == CA_STATUS_REINIT))
     2823    uint32_t uStatus = ASMAtomicReadU32(&pCAStream->status);
     2824    if (!(   uStatus == COREAUDIOSTATUS_INIT
     2825          || uStatus == COREAUDIOSTATUS_REINIT))
    21972826    {
    21982827        return VINF_SUCCESS;
     
    22082837        {
    22092838            /* Only start the device if it is actually stopped */
    2210             if (!coreAudioIsRunning(pStreamOut->deviceID))
    2211             {
    2212                 err = AudioUnitReset(pStreamOut->audioUnit, kAudioUnitScope_Input, 0);
     2839            if (!coreAudioUnitIsRunning(pCAStream))
     2840            {
     2841                err = AudioUnitReset(pCAStream->Unit.audioUnit, kAudioUnitScope_Input, 0);
    22132842                if (err != noErr)
    22142843                {
     
    22162845                    /* Keep going. */
    22172846                }
    2218                 RTCircBufReset(pStreamOut->pCircBuf);
    2219 
    2220                 err = AudioOutputUnitStart(pStreamOut->audioUnit);
     2847
     2848                RTCircBufReset(pCAStream->pCircBuf);
     2849
     2850                err = AudioOutputUnitStart(pCAStream->Unit.audioUnit);
    22212851                if (err != noErr)
    22222852                {
     
    22322862        {
    22332863            /* Only stop the device if it is actually running */
    2234             if (coreAudioIsRunning(pStreamOut->deviceID))
    2235             {
    2236                 err = AudioOutputUnitStop(pStreamOut->audioUnit);
     2864            if (coreAudioUnitIsRunning(pCAStream))
     2865            {
     2866                err = AudioOutputUnitStop(pCAStream->Unit.audioUnit);
    22372867                if (err != noErr)
    22382868                {
     
    22422872                }
    22432873
    2244                 err = AudioUnitReset(pStreamOut->audioUnit, kAudioUnitScope_Input, 0);
     2874                err = AudioUnitReset(pCAStream->Unit.audioUnit, kAudioUnitScope_Input, 0);
    22452875                if (err != noErr)
    22462876                {
     
    22612891}
    22622892
    2263 static int coreAudioControlStreamIn(PPDMAUDIOSTREAM pStream, PDMAUDIOSTREAMCMD enmStreamCmd)
    2264 {
    2265     PCOREAUDIOSTREAMIN pStreamIn = (PCOREAUDIOSTREAMIN)pStream;
    2266 
    2267     LogFlowFunc(("enmStreamCmd=%RU32\n", enmStreamCmd));
    2268 
    2269     uint32_t uStatus = ASMAtomicReadU32(&pStreamIn->status);
    2270     if (!(   uStatus == CA_STATUS_INIT
    2271           || uStatus == CA_STATUS_REINIT))
    2272     {
    2273         return VINF_SUCCESS;
    2274     }
    2275 
    2276     int rc = VINF_SUCCESS;
    2277 
    2278     OSStatus err;
    2279     switch (enmStreamCmd)
    2280     {
    2281         case PDMAUDIOSTREAMCMD_ENABLE:
    2282         case PDMAUDIOSTREAMCMD_RESUME:
    2283         {
    2284             /* Only start the device if it is actually stopped */
    2285             if (!coreAudioIsRunning(pStreamIn->deviceID))
    2286             {
    2287                 RTCircBufReset(pStreamIn->pCircBuf);
    2288                 err = AudioOutputUnitStart(pStreamIn->audioUnit);
    2289                 if (err != noErr)
    2290                 {
    2291                     LogRel(("CoreAudio: Failed to start recording (%RI32)\n", err));
    2292                     rc = VERR_GENERAL_FAILURE; /** @todo Fudge! */
    2293                     break;
    2294                 }
    2295             }
    2296 
    2297             break;
    2298         }
    2299 
    2300         case PDMAUDIOSTREAMCMD_DISABLE:
    2301         case PDMAUDIOSTREAMCMD_PAUSE:
    2302         {
    2303             /* Only stop the device if it is actually running */
    2304             if (coreAudioIsRunning(pStreamIn->deviceID))
    2305             {
    2306                 err = AudioOutputUnitStop(pStreamIn->audioUnit);
    2307                 if (err != noErr)
    2308                 {
    2309                     LogRel(("CoreAudio: Failed to stop recording (%RI32)\n", err));
    2310                     rc = VERR_GENERAL_FAILURE; /** @todo Fudge! */
    2311                     break;
    2312                 }
    2313 
    2314                 err = AudioUnitReset(pStreamIn->audioUnit, kAudioUnitScope_Input, 0);
    2315                 if (err != noErr)
    2316                 {
    2317                     LogRel(("CoreAudio: Failed to reset AudioUnit (%RI32)\n", err));
    2318                     rc = VERR_GENERAL_FAILURE; /** @todo Fudge! */
    2319                     break;
    2320                 }
    2321             }
    2322             break;
    2323         }
    2324 
    2325         default:
    2326             rc = VERR_NOT_SUPPORTED;
    2327             break;
    2328     }
    2329 
    2330     LogFlowFuncLeaveRC(rc);
    2331     return rc;
    2332 }
    2333 
    2334 static int coreAudioDestroyStreamIn(PPDMAUDIOSTREAM pStream)
    2335 {
    2336     PCOREAUDIOSTREAMIN pStreamIn = (PCOREAUDIOSTREAMIN)pStream;
    2337 
    2338     LogFlowFuncEnter();
    2339 
    2340     uint32_t status = ASMAtomicReadU32(&pStreamIn->status);
    2341     if (!(   status == CA_STATUS_INIT
    2342           || status == CA_STATUS_REINIT))
    2343     {
    2344         return VINF_SUCCESS;
    2345     }
    2346 
    2347     OSStatus err = noErr;
    2348 
    2349     int rc = coreAudioControlStreamIn(&pStreamIn->Stream, PDMAUDIOSTREAMCMD_DISABLE);
    2350     if (RT_SUCCESS(rc))
    2351     {
    2352         ASMAtomicXchgU32(&pStreamIn->status, CA_STATUS_IN_UNINIT);
    2353 
    2354         /*
    2355          * Unregister recording device callbacks.
    2356          */
    2357         AudioObjectPropertyAddress propAdr = { kAudioDeviceProcessorOverload, kAudioObjectPropertyScopeGlobal,
    2358                                                kAudioObjectPropertyElementMaster };
    2359 #ifdef DEBUG
    2360         err = AudioObjectRemovePropertyListener(pStreamIn->deviceID, &propAdr,
    2361                                                 coreAudioRecordingAudioDevicePropertyChanged, &pStreamIn->cbCtx);
    2362         if (   err != noErr
    2363             && err != kAudioHardwareBadObjectError)
    2364         {
    2365             LogRel(("CoreAudio: Failed to remove the recording processor overload listener (%RI32)\n", err));
    2366         }
    2367 #endif /* DEBUG */
    2368 
    2369         propAdr.mSelector = kAudioDevicePropertyNominalSampleRate;
    2370         err = AudioObjectRemovePropertyListener(pStreamIn->deviceID, &propAdr,
    2371                                                 coreAudioRecordingAudioDevicePropertyChanged, &pStreamIn->cbCtx);
    2372         if (   err != noErr
    2373             && err != kAudioHardwareBadObjectError)
    2374         {
    2375             LogRel(("CoreAudio: Failed to remove the recording sample rate changed listener (%RI32)\n", err));
    2376         }
    2377 
    2378         if (pStreamIn->fDefDevChgListReg)
    2379         {
    2380             propAdr.mSelector = kAudioHardwarePropertyDefaultInputDevice;
    2381             err = AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &propAdr,
    2382                                                     coreAudioDefaultDeviceChanged, &pStreamIn->cbCtx);
    2383             if (   err != noErr
    2384                 && err != kAudioHardwareBadObjectError)
    2385             {
    2386                 LogRel(("CoreAudio: Failed to remove the default recording device changed listener (%RI32)\n", err));
    2387             }
    2388 
    2389             pStreamIn->fDefDevChgListReg = false;
    2390         }
    2391 
    2392         if (pStreamIn->fDevStateChgListReg)
    2393         {
    2394             Assert(pStreamIn->deviceID != kAudioDeviceUnknown);
    2395 
    2396             AudioObjectPropertyAddress propAdr2 = { kAudioDevicePropertyDeviceIsAlive, kAudioObjectPropertyScopeGlobal,
    2397                                                     kAudioObjectPropertyElementMaster };
    2398             err = AudioObjectRemovePropertyListener(pStreamIn->deviceID, &propAdr2,
    2399                                                     drvHostCoreAudioDeviceStateChanged, &pStreamIn->cbCtx);
    2400             if (   err != noErr
    2401                 && err != kAudioHardwareBadObjectError)
    2402             {
    2403                 LogRel(("CoreAudio: Failed to remove the recording device state changed listener (%RI32)\n", err));
    2404             }
    2405 
    2406             pStreamIn->fDevStateChgListReg = false;
    2407         }
    2408 
    2409         if (pStreamIn->pConverter)
    2410         {
    2411             AudioConverterDispose(pStreamIn->pConverter);
    2412             pStreamIn->pConverter = NULL;
    2413         }
    2414 
    2415         err = AudioUnitUninitialize(pStreamIn->audioUnit);
    2416         if (err == noErr)
    2417             err = AudioComponentInstanceDispose(pStreamIn->audioUnit);
    2418 
    2419         if (   err != noErr
    2420             && err != kAudioHardwareBadObjectError)
    2421         {
    2422             LogRel(("CoreAudio: Failed to uninit the recording device (%RI32)\n", err));
    2423         }
    2424 
    2425         pStreamIn->deviceID      = kAudioDeviceUnknown;
    2426         pStreamIn->audioUnit     = NULL;
    2427         pStreamIn->sampleRatio   = 1;
    2428 
    2429         coreAudioUninitConvCbCtx(&pStreamIn->convCbCtx);
    2430 
    2431         if (pStreamIn->pCircBuf)
    2432         {
    2433             RTCircBufDestroy(pStreamIn->pCircBuf);
    2434             pStreamIn->pCircBuf = NULL;
    2435         }
    2436 
    2437         ASMAtomicXchgU32(&pStreamIn->status, CA_STATUS_UNINIT);
    2438     }
    2439     else
    2440     {
    2441         LogRel(("CoreAudio: Failed to stop recording on uninit (%RI32)\n", err));
    2442         rc = VERR_GENERAL_FAILURE; /** @todo Fudge! */
    2443     }
    2444 
    2445     LogFlowFuncLeaveRC(rc);
    2446     return rc;
    2447 }
    2448 
    2449 static int coreAudioDestroyStreamOut(PPDMAUDIOSTREAM pStream)
    2450 {
    2451     PCOREAUDIOSTREAMOUT pStreamOut = (PCOREAUDIOSTREAMOUT)pStream;
    2452 
    2453     LogFlowFuncEnter();
    2454 
    2455     uint32_t status = ASMAtomicReadU32(&pStreamOut->status);
    2456     if (!(   status == CA_STATUS_INIT
    2457           || status == CA_STATUS_REINIT))
    2458     {
    2459         return VINF_SUCCESS;
    2460     }
    2461 
    2462     int rc = coreAudioControlStreamOut(&pStreamOut->Stream, PDMAUDIOSTREAMCMD_DISABLE);
    2463     if (RT_SUCCESS(rc))
    2464     {
    2465         ASMAtomicXchgU32(&pStreamOut->status, CA_STATUS_IN_UNINIT);
    2466 
    2467         OSStatus err;
    2468 
    2469         /*
    2470          * Unregister playback device callbacks.
    2471          */
    2472         AudioObjectPropertyAddress propAdr = { kAudioDeviceProcessorOverload, kAudioObjectPropertyScopeGlobal,
    2473                                                kAudioObjectPropertyElementMaster };
    2474 #ifdef DEBUG
    2475         err = AudioObjectRemovePropertyListener(pStreamOut->deviceID, &propAdr,
    2476                                                 coreAudioPlaybackAudioDevicePropertyChanged, &pStreamOut->cbCtx);
    2477         if (   err != noErr
    2478             && err != kAudioHardwareBadObjectError)
    2479         {
    2480             LogRel(("CoreAudio: Failed to remove the playback processor overload listener (%RI32)\n", err));
    2481         }
    2482 #endif /* DEBUG */
    2483 
    2484         propAdr.mSelector = kAudioDevicePropertyNominalSampleRate;
    2485         err = AudioObjectRemovePropertyListener(pStreamOut->deviceID, &propAdr,
    2486                                                 coreAudioPlaybackAudioDevicePropertyChanged, &pStreamOut->cbCtx);
    2487         if (   err != noErr
    2488             && err != kAudioHardwareBadObjectError)
    2489         {
    2490             LogRel(("CoreAudio: Failed to remove the playback sample rate changed listener (%RI32)\n", err));
    2491         }
    2492 
    2493         if (pStreamOut->fDefDevChgListReg)
    2494         {
    2495             propAdr.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
    2496             propAdr.mScope    = kAudioObjectPropertyScopeGlobal;
    2497             propAdr.mElement  = kAudioObjectPropertyElementMaster;
    2498             err = AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &propAdr,
    2499                                                     coreAudioDefaultDeviceChanged, &pStreamOut->cbCtx);
    2500             if (   err != noErr
    2501                 && err != kAudioHardwareBadObjectError)
    2502             {
    2503                 LogRel(("CoreAudio: Failed to remove the default playback device changed listener (%RI32)\n", err));
    2504             }
    2505 
    2506             pStreamOut->fDefDevChgListReg = false;
    2507         }
    2508 
    2509         if (pStreamOut->fDevStateChgListReg)
    2510         {
    2511             Assert(pStreamOut->deviceID != kAudioDeviceUnknown);
    2512 
    2513             AudioObjectPropertyAddress propAdr2 = { kAudioDevicePropertyDeviceIsAlive, kAudioObjectPropertyScopeGlobal,
    2514                                                     kAudioObjectPropertyElementMaster };
    2515             err = AudioObjectRemovePropertyListener(pStreamOut->deviceID, &propAdr2,
    2516                                                     drvHostCoreAudioDeviceStateChanged, &pStreamOut->cbCtx);
    2517             if (   err != noErr
    2518                 && err != kAudioHardwareBadObjectError)
    2519             {
    2520                 LogRel(("CoreAudio: Failed to remove the playback device state changed listener (%RI32)\n", err));
    2521             }
    2522 
    2523             pStreamOut->fDevStateChgListReg = false;
    2524         }
    2525 
    2526         err = AudioUnitUninitialize(pStreamOut->audioUnit);
    2527         if (err == noErr)
    2528             err = AudioComponentInstanceDispose(pStreamOut->audioUnit);
    2529 
    2530         if (   err != noErr
    2531             && err != kAudioHardwareBadObjectError)
    2532         {
    2533             LogRel(("CoreAudio: Failed to uninit the playback device (%RI32)\n", err));
    2534         }
    2535 
    2536         pStreamOut->deviceID  = kAudioDeviceUnknown;
    2537         pStreamOut->audioUnit = NULL;
    2538         if (pStreamOut->pCircBuf)
    2539         {
    2540             RTCircBufDestroy(pStreamOut->pCircBuf);
    2541             pStreamOut->pCircBuf = NULL;
    2542         }
    2543 
    2544         ASMAtomicXchgU32(&pStreamOut->status, CA_STATUS_UNINIT);
    2545     }
    2546     else
    2547         LogRel(("CoreAudio: Failed to stop playback on uninit, rc=%Rrc\n", rc));
    2548 
    2549     LogFlowFuncLeaveRC(rc);
    2550     return rc;
    2551 }
    2552 
    2553 static int coreAudioCreateStreamIn(PDRVHOSTCOREAUDIO pThis,
    2554                                    PPDMAUDIOSTREAM pStream, PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
    2555 {
    2556     AssertPtrReturn(pThis,   VERR_INVALID_POINTER);
    2557     AssertPtrReturn(pStream, VERR_INVALID_POINTER);
    2558     AssertPtrReturn(pCfgReq, VERR_INVALID_POINTER);
    2559     AssertPtrReturn(pCfgAcq, VERR_INVALID_POINTER);
    2560 
    2561     PCOREAUDIOSTREAMIN pStreamIn = (PCOREAUDIOSTREAMIN)pStream;
    2562 
    2563     LogFlowFunc(("enmRecSource=%RU32\n", pCfgReq->DestSource.Source));
    2564 
    2565     pStreamIn->deviceID            = kAudioDeviceUnknown;
    2566     pStreamIn->audioUnit           = NULL;
    2567     pStreamIn->pConverter          = NULL;
    2568     pStreamIn->sampleRatio         = 1;
    2569     pStreamIn->pCircBuf            = NULL;
    2570     pStreamIn->status              = CA_STATUS_UNINIT;
    2571     pStreamIn->fDefDevChgListReg   = false;
    2572     pStreamIn->fDevStateChgListReg = false;
    2573 
    2574     /* Set callback context. */
    2575     pStreamIn->cbCtx.pThis  = pThis;
    2576     pStreamIn->cbCtx.enmDir = PDMAUDIODIR_IN;
    2577     pStreamIn->cbCtx.pIn    = pStreamIn;
    2578 
    2579     bool fDeviceByUser = false; /* Do we use a device which was set by the user? */
    2580 
    2581 #if 0
    2582     /* Try to find the audio device set by the user */
    2583     if (DeviceUID.pszInputDeviceUID)
    2584     {
    2585         pStreamIn->deviceID = drvHostCoreAudioDeviceUIDtoID(DeviceUID.pszInputDeviceUID);
    2586         /* Not fatal */
    2587         if (pStreamIn->deviceID == kAudioDeviceUnknown)
    2588             LogRel(("CoreAudio: Unable to find recording device %s. Falling back to the default audio device. \n", DeviceUID.pszInputDeviceUID));
    2589         else
    2590             fDeviceByUser = true;
    2591     }
    2592 #endif
    2593     int rc = coreAudioInitIn(pThis, &pStreamIn->Stream, pCfgReq, pCfgAcq);
    2594     if (RT_SUCCESS(rc))
    2595     {
    2596         OSStatus err;
    2597 
    2598         /* When the devices isn't forced by the user, we want default device change notifications. */
    2599         if (!fDeviceByUser)
    2600         {
    2601             if (!pStreamIn->fDefDevChgListReg)
    2602             {
    2603                 AudioObjectPropertyAddress propAdr = { kAudioHardwarePropertyDefaultInputDevice, kAudioObjectPropertyScopeGlobal,
    2604                                                        kAudioObjectPropertyElementMaster };
    2605                 err = AudioObjectAddPropertyListener(kAudioObjectSystemObject, &propAdr,
    2606                                                      coreAudioDefaultDeviceChanged, &pStreamIn->cbCtx);
    2607                 if (   err == noErr
    2608                     || err == kAudioHardwareIllegalOperationError)
    2609                 {
    2610                     pStreamIn->fDefDevChgListReg = true;
    2611                 }
    2612                 else
    2613                     LogRel(("CoreAudio: Failed to add the default recording device changed listener (%RI32)\n", err));
    2614             }
    2615         }
    2616 
    2617         if (   !pStreamIn->fDevStateChgListReg
    2618             && (pStreamIn->deviceID != kAudioDeviceUnknown))
    2619         {
    2620             /* Register callback for being notified if the device stops being alive. */
    2621             AudioObjectPropertyAddress propAdr = { kAudioDevicePropertyDeviceIsAlive, kAudioObjectPropertyScopeGlobal,
    2622                                                    kAudioObjectPropertyElementMaster };
    2623             err = AudioObjectAddPropertyListener(pStreamIn->deviceID, &propAdr, drvHostCoreAudioDeviceStateChanged,
    2624                                                  &pStreamIn->cbCtx);
    2625             if (err == noErr)
    2626             {
    2627                 pStreamIn->fDevStateChgListReg = true;
    2628             }
    2629             else
    2630                 LogRel(("CoreAudio: Failed to add the recording device state changed listener (%RI32)\n", err));
    2631         }
    2632     }
    2633 
    2634     LogFlowFuncLeaveRC(rc);
    2635     return rc;
    2636 }
    2637 
    2638 static int coreAudioCreateStreamOut(PDRVHOSTCOREAUDIO pThis,
    2639                                     PPDMAUDIOSTREAM pStream, PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
    2640 {
    2641     AssertPtrReturn(pThis,   VERR_INVALID_POINTER);
    2642     AssertPtrReturn(pStream, VERR_INVALID_POINTER);
    2643     AssertPtrReturn(pCfgReq, VERR_INVALID_POINTER);
    2644     AssertPtrReturn(pCfgAcq, VERR_INVALID_POINTER);
    2645 
    2646     PCOREAUDIOSTREAMOUT pStreamOut = (PCOREAUDIOSTREAMOUT)pStream;
    2647 
    2648     LogFlowFuncEnter();
    2649 
    2650     pStreamOut->deviceID            = kAudioDeviceUnknown;
    2651     pStreamOut->audioUnit           = NULL;
    2652     pStreamOut->pCircBuf            = NULL;
    2653     pStreamOut->status              = CA_STATUS_UNINIT;
    2654     pStreamOut->fDefDevChgListReg   = false;
    2655     pStreamOut->fDevStateChgListReg = false;
    2656 
    2657     /* Set callback context. */
    2658     pStreamOut->cbCtx.pThis  = pThis;
    2659     pStreamOut->cbCtx.enmDir = PDMAUDIODIR_OUT;
    2660     pStreamOut->cbCtx.pOut   = pStreamOut;
    2661 
    2662     bool fDeviceByUser = false; /* Do we use a device which was set by the user? */
    2663 
    2664 #if 0
    2665     /* Try to find the audio device set by the user. Use
    2666      * export VBOX_COREAUDIO_OUTPUT_DEVICE_UID=AppleHDAEngineOutput:0
    2667      * to set it. */
    2668     if (DeviceUID.pszOutputDeviceUID)
    2669     {
    2670         pStreamOut->audioDeviceId = drvHostCoreAudioDeviceUIDtoID(DeviceUID.pszOutputDeviceUID);
    2671         /* Not fatal */
    2672         if (pStreamOut->audioDeviceId == kAudioDeviceUnknown)
    2673             LogRel(("CoreAudio: Unable to find playback device %s. Falling back to the default audio device. \n", DeviceUID.pszOutputDeviceUID));
    2674         else
    2675             fDeviceByUser = true;
    2676     }
    2677 #endif
    2678     int rc = coreAudioInitOut(pThis, pStream, pCfgReq, pCfgAcq);
    2679     if (RT_SUCCESS(rc))
    2680     {
    2681         OSStatus err;
    2682 
    2683         /* When the devices isn't forced by the user, we want default device change notifications. */
    2684         if (!fDeviceByUser)
    2685         {
    2686             AudioObjectPropertyAddress propAdr = { kAudioHardwarePropertyDefaultOutputDevice, kAudioObjectPropertyScopeGlobal,
    2687                                                    kAudioObjectPropertyElementMaster };
    2688             err = AudioObjectAddPropertyListener(kAudioObjectSystemObject, &propAdr,
    2689                                                  coreAudioDefaultDeviceChanged, &pStreamOut->cbCtx);
    2690             if (err == noErr)
    2691             {
    2692                 pStreamOut->fDefDevChgListReg = true;
    2693             }
    2694             else
    2695                 LogRel(("CoreAudio: Failed to add the default playback device changed listener (%RI32)\n", err));
    2696         }
    2697 
    2698         if (   !pStreamOut->fDevStateChgListReg
    2699             && (pStreamOut->deviceID != kAudioDeviceUnknown))
    2700         {
    2701             /* Register callback for being notified if the device stops being alive. */
    2702             AudioObjectPropertyAddress propAdr = { kAudioDevicePropertyDeviceIsAlive, kAudioObjectPropertyScopeGlobal,
    2703                                                    kAudioObjectPropertyElementMaster };
    2704             err = AudioObjectAddPropertyListener(pStreamOut->deviceID, &propAdr, drvHostCoreAudioDeviceStateChanged,
    2705                                                  (void *)&pStreamOut->cbCtx);
    2706             if (err == noErr)
    2707             {
    2708                 pStreamOut->fDevStateChgListReg = true;
    2709             }
    2710             else
    2711                 LogRel(("CoreAudio: Failed to add the playback device state changed listener (%RI32)\n", err));
    2712         }
    2713     }
    2714 
    2715     LogFlowFuncLeaveRC(rc);
    2716     return rc;
    2717 }
    2718 
    27192893
    27202894/**
     
    27262900    AssertPtrReturn(pBackendCfg, VERR_INVALID_POINTER);
    27272901
     2902    RT_BZERO(pBackendCfg, sizeof(PDMAUDIOBACKENDCFG));
     2903
     2904    pBackendCfg->cbStreamIn  = sizeof(COREAUDIOSTREAM);
     2905    pBackendCfg->cbStreamOut = sizeof(COREAUDIOSTREAM);
     2906
     2907    pBackendCfg->cMaxStreamsIn  = UINT32_MAX;
     2908    pBackendCfg->cMaxStreamsOut = UINT32_MAX;
     2909
     2910    LogFlowFunc(("Returning %Rrc\n", VINF_SUCCESS));
     2911    return VINF_SUCCESS;
     2912}
     2913
     2914
     2915/**
     2916 * @interface_method_impl{PDMIHOSTAUDIO, pfnGetDevices}
     2917 */
     2918static DECLCALLBACK(int) drvHostCoreAudioGetDevices(PPDMIHOSTAUDIO pInterface, PPDMAUDIODEVICEENUM pDeviceEnum)
     2919{
     2920    AssertPtrReturn(pInterface,  VERR_INVALID_POINTER);
     2921    AssertPtrReturn(pDeviceEnum, VERR_INVALID_POINTER);
     2922
    27282923    PDRVHOSTCOREAUDIO pThis = PDMIHOSTAUDIO_2_DRVHOSTCOREAUDIO(pInterface);
    27292924
    2730     return coreAudioUpdateStatusInternalEx(pThis, pBackendCfg, 0 /* fEnum */);
    2731 }
     2925    return coreAudioDevicesEnumerateAll(pThis, pDeviceEnum);
     2926}
     2927
     2928
     2929#ifdef VBOX_WITH_AUDIO_CALLBACKS
     2930/**
     2931 * @interface_method_impl{PDMIHOSTAUDIO, pfnSetCallback}
     2932 */
     2933static DECLCALLBACK(int) drvHostCoreAudioSetCallback(PPDMIHOSTAUDIO pInterface, PFNPDMHOSTAUDIOCALLBACK pfnCallback)
     2934{
     2935    AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
     2936    /* pfnCallback will be handled below. */
     2937
     2938    PDRVHOSTCOREAUDIO pThis = PDMIHOSTAUDIO_2_DRVHOSTCOREAUDIO(pInterface);
     2939
     2940    int rc = RTCritSectEnter(&pThis->CritSect);
     2941    if (RT_SUCCESS(rc))
     2942    {
     2943        LogFunc(("pfnCallback=%p\n", pfnCallback));
     2944
     2945        if (pfnCallback) /* Register. */
     2946        {
     2947            Assert(pThis->pfnCallback == NULL);
     2948            pThis->pfnCallback = pfnCallback;
     2949        }
     2950        else /* Unregister. */
     2951        {
     2952            if (pThis->pfnCallback)
     2953                pThis->pfnCallback = NULL;
     2954        }
     2955
     2956        int rc2 = RTCritSectLeave(&pThis->CritSect);
     2957        AssertRC(rc2);
     2958    }
     2959
     2960    return rc;
     2961}
     2962#endif
    27322963
    27332964
     
    27482979 */
    27492980static DECLCALLBACK(int) drvHostCoreAudioStreamCreate(PPDMIHOSTAUDIO pInterface,
    2750                                                       PPDMAUDIOSTREAM pStream,
    2751                                                       PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
     2981                                                      PPDMAUDIOSTREAM pStream, PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
    27522982{
    27532983    AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
     
    27582988    PDRVHOSTCOREAUDIO pThis = PDMIHOSTAUDIO_2_DRVHOSTCOREAUDIO(pInterface);
    27592989
     2990    Assert(pStream->enmCtx == PDMAUDIOSTREAMCTX_HOST);
     2991
     2992    PCOREAUDIOSTREAM  pCAStream = (PCOREAUDIOSTREAM)pStream;
     2993
    27602994    int rc;
    2761     if (pCfgReq->enmDir == PDMAUDIODIR_IN)
    2762         rc = coreAudioCreateStreamIn(pThis,  pStream, pCfgReq, pCfgAcq);
    2763     else
    2764         rc = coreAudioCreateStreamOut(pThis, pStream, pCfgReq, pCfgAcq);
     2995
     2996    /* Input or output device? */
     2997    bool fIn = pCfgReq->enmDir == PDMAUDIODIR_IN;
     2998
     2999    /* For now, just use the default device available. */
     3000    PPDMAUDIODEVICE pDev = fIn ? pThis->pDefaultDevIn : pThis->pDefaultDevOut;
     3001
     3002    /* Init the Core Audio stream. */
     3003    rc = coreAudioStreamInit(pCAStream, pThis, pDev);
     3004    if (RT_SUCCESS(rc))
     3005    {
     3006        if (pDev) /* (Default) device available? */
     3007        {
     3008            /* Sanity. */
     3009            AssertPtr(pDev->pvData);
     3010            Assert(pDev->cbData);
     3011
     3012            if (RT_SUCCESS(rc))
     3013            {
     3014                if (fIn)
     3015                    rc = coreAudioStreamInitIn (pCAStream, pCfgReq, pCfgAcq);
     3016                else
     3017                    rc = coreAudioStreamInitOut(pCAStream, pCfgReq, pCfgAcq);
     3018
     3019                if (RT_FAILURE(rc))
     3020                {
     3021                    int rc2 = coreAudioStreamUninit(pCAStream);
     3022                    AssertRC(rc2);
     3023                }
     3024            }
     3025        }
     3026        else
     3027            rc = VERR_NOT_AVAILABLE;
     3028    }
    27653029
    27663030    LogFlowFunc(("%s: rc=%Rrc\n", pStream->szName, rc));
     
    27773041    AssertPtrReturn(pStream,    VERR_INVALID_POINTER);
    27783042
    2779     int rc;
    2780     if (pStream->enmDir == PDMAUDIODIR_IN)
    2781         rc = coreAudioDestroyStreamIn(pStream);
    2782     else
    2783         rc = coreAudioDestroyStreamOut(pStream);
    2784 
     3043    PDRVHOSTCOREAUDIO pThis = PDMIHOSTAUDIO_2_DRVHOSTCOREAUDIO(pInterface);
     3044
     3045    Assert(pStream->enmCtx == PDMAUDIOSTREAMCTX_HOST);
     3046
     3047    PCOREAUDIOSTREAM pCAStream = (PCOREAUDIOSTREAM)pStream;
     3048
     3049    uint32_t status = ASMAtomicReadU32(&pCAStream->status);
     3050    if (!(   status == COREAUDIOSTATUS_INIT
     3051          || status == COREAUDIOSTATUS_REINIT))
     3052    {
     3053        return VINF_SUCCESS;
     3054    }
     3055
     3056    int rc = coreAudioStreamControl(pThis, pCAStream, PDMAUDIOSTREAMCMD_DISABLE);
     3057    if (RT_SUCCESS(rc))
     3058    {
     3059        ASMAtomicXchgU32(&pCAStream->status, COREAUDIOSTATUS_IN_UNINIT);
     3060
     3061        rc = coreAudioStreamUninit(pCAStream);
     3062        if (RT_SUCCESS(rc))
     3063            ASMAtomicXchgU32(&pCAStream->status, COREAUDIOSTATUS_UNINIT);
     3064    }
     3065
     3066    LogFlowFunc(("%s: rc=%Rrc\n", pStream->szName, rc));
    27853067    return rc;
    27863068}
     
    27963078    AssertPtrReturn(pStream,    VERR_INVALID_POINTER);
    27973079
     3080    PDRVHOSTCOREAUDIO pThis = PDMIHOSTAUDIO_2_DRVHOSTCOREAUDIO(pInterface);
     3081
    27983082    Assert(pStream->enmCtx == PDMAUDIOSTREAMCTX_HOST);
    27993083
    2800     int rc;
    2801     if (pStream->enmDir == PDMAUDIODIR_IN)
    2802         rc = coreAudioControlStreamIn(pStream, enmStreamCmd);
    2803     else
    2804         rc = coreAudioControlStreamOut(pStream, enmStreamCmd);
    2805 
    2806     return rc;
     3084    PCOREAUDIOSTREAM pCAStream = (PCOREAUDIOSTREAM)pStream;
     3085
     3086    return coreAudioStreamControl(pThis, pCAStream, enmStreamCmd);
    28073087}
    28083088
     
    28203100    PDMAUDIOSTRMSTS strmSts = PDMAUDIOSTRMSTS_FLAG_NONE;
    28213101
     3102    PCOREAUDIOSTREAM pCAStream = (PCOREAUDIOSTREAM)pStream;
     3103
     3104    if (ASMAtomicReadU32(&pCAStream->status) == COREAUDIOSTATUS_INIT)
     3105        strmSts |= PDMAUDIOSTRMSTS_FLAG_INITIALIZED | PDMAUDIOSTRMSTS_FLAG_ENABLED;
     3106
    28223107    if (pStream->enmDir == PDMAUDIODIR_IN)
    28233108    {
    2824         PCOREAUDIOSTREAMIN pStreamIn = (PCOREAUDIOSTREAMIN)pStream;
    2825 
    2826         if (ASMAtomicReadU32(&pStreamIn->status) == CA_STATUS_INIT)
    2827             strmSts |= PDMAUDIOSTRMSTS_FLAG_INITIALIZED | PDMAUDIOSTRMSTS_FLAG_ENABLED;
    2828 
    28293109        if (strmSts & PDMAUDIOSTRMSTS_FLAG_ENABLED)
    28303110            strmSts |= PDMAUDIOSTRMSTS_FLAG_DATA_READABLE;
     
    28323112    else if (pStream->enmDir == PDMAUDIODIR_OUT)
    28333113    {
    2834         PCOREAUDIOSTREAMOUT pStreamOut = (PCOREAUDIOSTREAMOUT)pStream;
    2835 
    2836         if (ASMAtomicReadU32(&pStreamOut->status) == CA_STATUS_INIT)
    2837             strmSts |= PDMAUDIOSTRMSTS_FLAG_INITIALIZED | PDMAUDIOSTRMSTS_FLAG_ENABLED;
    2838 
    28393114        if (strmSts & PDMAUDIOSTRMSTS_FLAG_ENABLED)
    28403115            strmSts |= PDMAUDIOSTRMSTS_FLAG_DATA_WRITABLE;
     
    28613136
    28623137/**
     3138 * @interface_method_impl{PDMIHOSTAUDIO, pfnInit}
     3139 */
     3140static DECLCALLBACK(int) drvHostCoreAudioInit(PPDMIHOSTAUDIO pInterface)
     3141{
     3142    PDRVHOSTCOREAUDIO pThis = PDMIHOSTAUDIO_2_DRVHOSTCOREAUDIO(pInterface);
     3143
     3144    int rc = DrvAudioHlpDeviceEnumInit(&pThis->Devices);
     3145    if (RT_SUCCESS(rc))
     3146    {
     3147        /* Enumerate all devices internally. */
     3148        rc = coreAudioDevicesEnumerateAll(pThis, &pThis->Devices);
     3149        if (RT_SUCCESS(rc))
     3150        {
     3151            if (pThis->pDefaultDevIn)
     3152                coreAudioDeviceUnregisterCallbacks(pThis, pThis->pDefaultDevIn);
     3153
     3154            pThis->pDefaultDevIn  = DrvAudioHlpDeviceEnumGetDefaultDevice(&pThis->Devices, PDMAUDIODIR_IN);
     3155            if (pThis->pDefaultDevIn)
     3156            {
     3157#ifdef DEBUG
     3158                PCOREAUDIODEVICEDATA pDevData = (PCOREAUDIODEVICEDATA)pThis->pDefaultDevIn;
     3159                AssertPtr(pDevData);
     3160                LogFunc(("defaultDevIn ID=%RU32\n", pDevData->deviceID));
     3161#endif
     3162                rc = coreAudioDeviceRegisterCallbacks(pThis, pThis->pDefaultDevIn);
     3163            }
     3164            else
     3165                LogRel2(("CoreAudio: No initial default capturing device found!\n"));
     3166
     3167            if (pThis->pDefaultDevOut)
     3168                coreAudioDeviceUnregisterCallbacks(pThis, pThis->pDefaultDevOut);
     3169
     3170            pThis->pDefaultDevOut = DrvAudioHlpDeviceEnumGetDefaultDevice(&pThis->Devices, PDMAUDIODIR_OUT);
     3171            if (pThis->pDefaultDevOut)
     3172            {
     3173#ifdef DEBUG
     3174                PCOREAUDIODEVICEDATA pDevData = (PCOREAUDIODEVICEDATA)pThis->pDefaultDevOut;
     3175                AssertPtr(pDevData);
     3176
     3177                LogFunc(("defaultDevOut ID=%RU32\n", pDevData->deviceID));
     3178#endif
     3179                rc = coreAudioDeviceRegisterCallbacks(pThis, pThis->pDefaultDevOut);
     3180            }
     3181            else
     3182                LogRel2(("CoreAudio: No initial default playback device found!\n"));
     3183        }
     3184    }
     3185
     3186    if (RT_SUCCESS(rc))
     3187    {
     3188        /* Register system callbacks. */
     3189        AudioObjectPropertyAddress propAdr = { kAudioHardwarePropertyDefaultInputDevice, kAudioObjectPropertyScopeGlobal,
     3190                                               kAudioObjectPropertyElementMaster };
     3191
     3192        OSStatus err = AudioObjectAddPropertyListener(kAudioObjectSystemObject, &propAdr,
     3193                                                      coreAudioDefaultDeviceChangedCb, pThis /* pvUser */);
     3194        if (   err != noErr
     3195            && err != kAudioHardwareIllegalOperationError)
     3196        {
     3197            LogRel(("CoreAudio: Failed to add the input default device changed listener (%RI32)\n", err));
     3198        }
     3199
     3200        propAdr.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
     3201        err = AudioObjectAddPropertyListener(kAudioObjectSystemObject, &propAdr,
     3202                                             coreAudioDefaultDeviceChangedCb, pThis /* pvUser */);
     3203        if (   err != noErr
     3204            && err != kAudioHardwareIllegalOperationError)
     3205        {
     3206            LogRel(("CoreAudio: Failed to add the output default device changed listener (%RI32)\n", err));
     3207        }
     3208    }
     3209
     3210    LogFlowFunc(("Returning %Rrc\n", rc));
     3211    return rc;
     3212}
     3213
     3214
     3215/**
    28633216 * @interface_method_impl{PDMIHOSTAUDIO, pfnShutdown}
    28643217 */
    28653218static DECLCALLBACK(void) drvHostCoreAudioShutdown(PPDMIHOSTAUDIO pInterface)
    28663219{
    2867     RT_NOREF(pInterface);
     3220    PDRVHOSTCOREAUDIO pThis = PDMIHOSTAUDIO_2_DRVHOSTCOREAUDIO(pInterface);
     3221
     3222    /*
     3223     * Unregister system callbacks.
     3224     */
     3225    AudioObjectPropertyAddress propAdr = { kAudioHardwarePropertyDefaultInputDevice, kAudioObjectPropertyScopeGlobal,
     3226                                           kAudioObjectPropertyElementMaster };
     3227
     3228    OSStatus err = AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &propAdr,
     3229                                                     coreAudioDefaultDeviceChangedCb, pThis /* pvUser */);
     3230    if (   err != noErr
     3231        && err != kAudioHardwareBadObjectError)
     3232    {
     3233        LogRel(("CoreAudio: Failed to remove the default input device changed listener (%RI32)\n", err));
     3234    }
     3235
     3236    propAdr.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
     3237    err = AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &propAdr,
     3238                                            coreAudioDefaultDeviceChangedCb, pThis /* pvUser */);
     3239    if (   err != noErr
     3240        && err != kAudioHardwareBadObjectError)
     3241    {
     3242        LogRel(("CoreAudio: Failed to remove the default output device changed listener (%RI32)\n", err));
     3243    }
     3244
     3245    LogFlowFuncEnter();
    28683246}
    28693247
     
    28743252static DECLCALLBACK(void *) drvHostCoreAudioQueryInterface(PPDMIBASE pInterface, const char *pszIID)
    28753253{
    2876     PPDMDRVINS          pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
    2877     PDRVHOSTCOREAUDIO   pThis   = PDMINS_2_DATA(pDrvIns, PDRVHOSTCOREAUDIO);
    2878 
    2879     PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
     3254    PPDMDRVINS        pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
     3255    PDRVHOSTCOREAUDIO pThis   = PDMINS_2_DATA(pDrvIns, PDRVHOSTCOREAUDIO);
     3256
     3257    PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE,      &pDrvIns->IBase);
    28803258    PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHOSTAUDIO, &pThis->IHostAudio);
    28813259
     
    28833261}
    28843262
     3263
    28853264/**
    28863265 * @callback_method_impl{FNPDMDRVCONSTRUCT,
    2887  *      Construct a DirectSound Audio driver instance.}
     3266 *      Construct a Core Audio driver instance.}
    28883267 */
    28893268static DECLCALLBACK(int) drvHostCoreAudioConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
     
    29033282    PDMAUDIO_IHOSTAUDIO_CALLBACKS(drvHostCoreAudio);
    29043283
    2905     return VINF_SUCCESS;
    2906 }
     3284    /* This backend supports device enumeration. */
     3285    pThis->IHostAudio.pfnGetDevices  = drvHostCoreAudioGetDevices;
     3286
     3287#ifdef VBOX_WITH_AUDIO_CALLBACKS
     3288    /* This backend supports host audio callbacks. */
     3289    pThis->IHostAudio.pfnSetCallback = drvHostCoreAudioSetCallback;
     3290    pThis->pfnCallback               = NULL;
     3291#endif
     3292
     3293    int rc = RTCritSectInit(&pThis->CritSect);
     3294
     3295    LogFlowFuncLeaveRC(rc);
     3296    return rc;
     3297}
     3298
     3299
     3300/**
     3301 * @callback_method_impl{FNPDMDRVDESTRUCT}
     3302 */
     3303static DECLCALLBACK(void) drvHostCoreAudioDestruct(PPDMDRVINS pDrvIns)
     3304{
     3305    PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
     3306    PDRVHOSTCOREAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTCOREAUDIO);
     3307
     3308    int rc2 = RTCritSectDelete(&pThis->CritSect);
     3309    AssertRC(rc2);
     3310
     3311    LogFlowFuncLeaveRC(rc2);
     3312}
     3313
    29073314
    29083315/**
     
    29223329    "Core Audio host driver",
    29233330    /* fFlags */
    2924      PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
     3331    PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
    29253332    /* fClass. */
    29263333    PDM_DRVREG_CLASS_AUDIO,
     
    29323339    drvHostCoreAudioConstruct,
    29333340    /* pfnDestruct */
    2934     NULL,
     3341    drvHostCoreAudioDestruct,
    29353342    /* pfnRelocate */
    29363343    NULL,
  • trunk/src/VBox/Devices/Audio/DrvHostDSound.cpp

    r63534 r63711  
    14241424#endif
    14251425
    1426         Cfg.cSources       = cbCtx.cDevIn;
    1427         Cfg.cSinks         = cbCtx.cDevOut;
    14281426        Cfg.cMaxStreamsIn  = UINT32_MAX;
    14291427        Cfg.cMaxStreamsOut = UINT32_MAX;
     
    20122010                        && cbFree)
    20132011                    {
    2014                         PDMAUDIOCALLBACKDATAOUT Out;
     2012                        PDMAUDIOCBDATA_DATA_OUTPUT Out;
    20152013                        Out.cbInFree     = cbFree;
    20162014                        Out.cbOutWritten = 0;
  • trunk/src/VBox/Devices/Audio/DrvHostDebugAudio.cpp

    r63629 r63711  
    8282    pBackendCfg->cbStreamOut    = sizeof(DEBUGAUDIOSTREAM);
    8383    pBackendCfg->cbStreamIn     = sizeof(DEBUGAUDIOSTREAM);
    84 
    85     /* The NULL backend has exactly one input source and one output sink. */
    86     pBackendCfg->cSources       = 1;
    87     pBackendCfg->cSinks         = 1;
    8884
    8985    pBackendCfg->cMaxStreamsOut = 1; /* Output */
  • trunk/src/VBox/Devices/Audio/DrvHostNullAudio.cpp

    r63549 r63711  
    106106    pBackendCfg->cbStreamOut    = sizeof(NULLAUDIOSTREAMOUT);
    107107    pBackendCfg->cbStreamIn     = sizeof(NULLAUDIOSTREAMIN);
    108 
    109     /* The NULL backend has exactly one input source and one output sink. */
    110     pBackendCfg->cSources       = 1;
    111     pBackendCfg->cSinks         = 1;
    112108
    113109    pBackendCfg->cMaxStreamsOut = 1; /* Output */
  • trunk/src/VBox/Devices/Audio/DrvHostOSSAudio.cpp

    r63534 r63711  
    589589    pBackendCfg->cbStreamOut = sizeof(OSSAUDIOSTREAMOUT);
    590590
    591     pBackendCfg->cSources    = 0;
    592     pBackendCfg->cSinks      = 0;
    593 
    594591    int hFile = open("/dev/dsp", O_WRONLY | O_NONBLOCK, 0);
    595592    if (hFile == -1)
     
    623620                    cDev = ossInfo.numaudios;
    624621
    625                 pBackendCfg->cSources        = cDev;
    626                 pBackendCfg->cSinks          = cDev;
    627 
    628622                pBackendCfg->cMaxStreamsIn   = UINT32_MAX;
    629623                pBackendCfg->cMaxStreamsOut  = UINT32_MAX;
     
    634628                /* Since we cannot query anything, assume that we have at least
    635629                 * one input and one output if we found "/dev/dsp" or "/dev/mixer". */
    636                 pBackendCfg->cSources        = 1;
    637                 pBackendCfg->cSinks          = 1;
    638630
    639631                pBackendCfg->cMaxStreamsIn   = UINT32_MAX;
  • trunk/src/VBox/Devices/Audio/DrvHostPulseAudio.cpp

    r63534 r63711  
    11061106        if (RT_SUCCESS(rc))
    11071107        {
    1108             Cfg.cSinks   = cbCtx.cDevOut;
    1109             Cfg.cSources = cbCtx.cDevIn;
    1110 
    11111108            if (fLog)
    11121109            {
  • trunk/src/VBox/Devices/Makefile.kmk

    r63689 r63711  
    536536 endif
    537537
     538 # Enable generic callback support.
     539 VBoxDD_DEFS  += VBOX_WITH_AUDIO_CALLBACKS
     540
     541 # Not yet enabled: Callbacks for the device emulation to let the backends
     542 #                  tell the emulation when and how to process data.
     543 if 0
     544  VBOX_DEFS   += VBOX_WITH_AUDIO_DEVICE_CALLBACKS
     545  VBOX_DEFS   += VBOX_WITH_AUDIO_SB16_CALLBACKS
     546  VBOX_DEFS   += VBOX_WITH_AUDIO_AC97_CALLBACKS
     547  VBOX_DEFS   += VBOX_WITH_AUDIO_HDA_CALLBACKS
     548 endif
     549 
    538550 VBoxDD_SOURCES         += \
    539551        Audio/DevIchAc97.cpp \
  • trunk/src/VBox/Main/src-client/DrvAudioVRDE.cpp

    r63534 r63711  
    363363    pBackendCfg->cMaxStreamsIn  = UINT32_MAX;
    364364    pBackendCfg->cMaxStreamsOut = UINT32_MAX;
    365     pBackendCfg->cSources       = 1;
    366     pBackendCfg->cSinks         = 1;
    367365
    368366    return VINF_SUCCESS;
     
    629627     */
    630628    void *pvUser;
    631     int rc = CFGMR3QueryPtr(pCfg, "ObjectVRDPServer", &pvUser);
     629    int rc = CFGMR3QueryPtr(pCfg, "ObjectVRDPServer", &pvUser); /** @todo r=andy Get rid of this hack and use IHostAudio::SetCallback. */
    632630    AssertMsgRCReturn(rc, ("Confguration error: No/bad \"ObjectVRDPServer\" value, rc=%Rrc\n", rc), rc);
    633631
     
    639637     */
    640638    pvUser = NULL;
    641     rc = CFGMR3QueryPtr(pCfg, "Object", &pvUser);
     639    rc = CFGMR3QueryPtr(pCfg, "Object", &pvUser); /** @todo r=andy Get rid of this hack and use IHostAudio::SetCallback. */
    642640    AssertMsgRCReturn(rc, ("Confguration error: No/bad \"Object\" value, rc=%Rrc\n", rc), rc);
    643641
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