MHFS-XS

 view release on metacpan or  search on metacpan

miniaudio/miniaudio.h  view on Meta::CPAN


This flag should always be used for platforms that do not support multithreading.
*/
typedef enum
{
    MA_JOB_QUEUE_FLAG_NON_BLOCKING = 0x00000001
} ma_job_queue_flags;

typedef struct
{
    ma_uint32 flags;
    ma_uint32 capacity; /* The maximum number of jobs that can fit in the queue at a time. */
} ma_job_queue_config;

MA_API ma_job_queue_config ma_job_queue_config_init(ma_uint32 flags, ma_uint32 capacity);


typedef struct
{
    ma_uint32 flags;                /* Flags passed in at initialization time. */
    ma_uint32 capacity;             /* The maximum number of jobs that can fit in the queue at a time. Set by the config. */
    MA_ATOMIC(8, ma_uint64) head;   /* The first item in the list. Required for removing from the top of the list. */
    MA_ATOMIC(8, ma_uint64) tail;   /* The last item in the list. Required for appending to the end of the list. */
#ifndef MA_NO_THREADING
    ma_semaphore sem;               /* Only used when MA_JOB_QUEUE_FLAG_NON_BLOCKING is unset. */
#endif
    ma_slot_allocator allocator;
    ma_job* pJobs;
#ifndef MA_USE_EXPERIMENTAL_LOCK_FREE_JOB_QUEUE
    ma_spinlock lock;
#endif

    /* Memory management. */
    void* _pHeap;
    ma_bool32 _ownsHeap;
} ma_job_queue;

MA_API ma_result ma_job_queue_get_heap_size(const ma_job_queue_config* pConfig, size_t* pHeapSizeInBytes);
MA_API ma_result ma_job_queue_init_preallocated(const ma_job_queue_config* pConfig, void* pHeap, ma_job_queue* pQueue);
MA_API ma_result ma_job_queue_init(const ma_job_queue_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_job_queue* pQueue);
MA_API void ma_job_queue_uninit(ma_job_queue* pQueue, const ma_allocation_callbacks* pAllocationCallbacks);
MA_API ma_result ma_job_queue_post(ma_job_queue* pQueue, const ma_job* pJob);
MA_API ma_result ma_job_queue_next(ma_job_queue* pQueue, ma_job* pJob); /* Returns MA_CANCELLED if the next job is a quit job. */



/************************************************************************************************************************************************************
*************************************************************************************************************************************************************

DEVICE I/O
==========

This section contains the APIs for device playback and capture. Here is where you'll find ma_device_init(), etc.

*************************************************************************************************************************************************************
************************************************************************************************************************************************************/
#ifndef MA_NO_DEVICE_IO
/* Some backends are only supported on certain platforms. */
#if defined(MA_WIN32)
    #define MA_SUPPORT_WASAPI
    #if defined(MA_WIN32_DESKTOP)  /* DirectSound and WinMM backends are only supported on desktops. */
        #define MA_SUPPORT_DSOUND
        #define MA_SUPPORT_WINMM
        #define MA_SUPPORT_JACK    /* JACK is technically supported on Windows, but I don't know how many people use it in practice... */
    #endif
#endif
#if defined(MA_UNIX)
    #if defined(MA_LINUX)
        #if !defined(MA_ANDROID)   /* ALSA is not supported on Android. */
            #define MA_SUPPORT_ALSA
        #endif
    #endif
    #if !defined(MA_BSD) && !defined(MA_ANDROID) && !defined(MA_EMSCRIPTEN)
        #define MA_SUPPORT_PULSEAUDIO
        #define MA_SUPPORT_JACK
    #endif
    #if defined(MA_ANDROID)
        #define MA_SUPPORT_AAUDIO
        #define MA_SUPPORT_OPENSL
    #endif
    #if defined(__OpenBSD__)        /* <-- Change this to "#if defined(MA_BSD)" to enable sndio on all BSD flavors. */
        #define MA_SUPPORT_SNDIO    /* sndio is only supported on OpenBSD for now. May be expanded later if there's demand. */
    #endif
    #if defined(__NetBSD__) || defined(__OpenBSD__)
        #define MA_SUPPORT_AUDIO4   /* Only support audio(4) on platforms with known support. */
    #endif
    #if defined(__FreeBSD__) || defined(__DragonFly__)
        #define MA_SUPPORT_OSS      /* Only support OSS on specific platforms with known support. */
    #endif
#endif
#if defined(MA_APPLE)
    #define MA_SUPPORT_COREAUDIO
#endif
#if defined(MA_EMSCRIPTEN)
    #define MA_SUPPORT_WEBAUDIO
#endif

/* All platforms should support custom backends. */
#define MA_SUPPORT_CUSTOM

/* Explicitly disable the Null backend for Emscripten because it uses a background thread which is not properly supported right now. */
#if !defined(MA_EMSCRIPTEN)
#define MA_SUPPORT_NULL
#endif


#if defined(MA_SUPPORT_WASAPI) && !defined(MA_NO_WASAPI) && (!defined(MA_ENABLE_ONLY_SPECIFIC_BACKENDS) || defined(MA_ENABLE_WASAPI))
    #define MA_HAS_WASAPI
#endif
#if defined(MA_SUPPORT_DSOUND) && !defined(MA_NO_DSOUND) && (!defined(MA_ENABLE_ONLY_SPECIFIC_BACKENDS) || defined(MA_ENABLE_DSOUND))
    #define MA_HAS_DSOUND
#endif
#if defined(MA_SUPPORT_WINMM) && !defined(MA_NO_WINMM) && (!defined(MA_ENABLE_ONLY_SPECIFIC_BACKENDS) || defined(MA_ENABLE_WINMM))
    #define MA_HAS_WINMM
#endif
#if defined(MA_SUPPORT_ALSA) && !defined(MA_NO_ALSA) && (!defined(MA_ENABLE_ONLY_SPECIFIC_BACKENDS) || defined(MA_ENABLE_ALSA))
    #define MA_HAS_ALSA
#endif
#if defined(MA_SUPPORT_PULSEAUDIO) && !defined(MA_NO_PULSEAUDIO) && (!defined(MA_ENABLE_ONLY_SPECIFIC_BACKENDS) || defined(MA_ENABLE_PULSEAUDIO))
    #define MA_HAS_PULSEAUDIO
#endif

miniaudio/miniaudio.h  view on Meta::CPAN

        ma_CoTaskMemFree(pContext, iidStr);
        ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to create event for waiting for ActivateAudioInterfaceAsync().");
        return result;
    }

#if defined(__cplusplus)
    hr = ActivateAudioInterfaceAsync(iidStr, MA_IID_IAudioClient, NULL, (IActivateAudioInterfaceCompletionHandler*)&completionHandler, (IActivateAudioInterfaceAsyncOperation**)&pAsyncOp);
#else
    hr = ActivateAudioInterfaceAsync(iidStr, &MA_IID_IAudioClient, NULL, (IActivateAudioInterfaceCompletionHandler*)&completionHandler, (IActivateAudioInterfaceAsyncOperation**)&pAsyncOp);
#endif
    if (FAILED(hr)) {
        ma_completion_handler_uwp_uninit(&completionHandler);
        ma_CoTaskMemFree(pContext, iidStr);
        ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[WASAPI] ActivateAudioInterfaceAsync() failed.");
        return ma_result_from_HRESULT(hr);
    }

    ma_CoTaskMemFree(pContext, iidStr);

    /* Wait for the async operation for finish. */
    ma_completion_handler_uwp_wait(&completionHandler);
    ma_completion_handler_uwp_uninit(&completionHandler);

    hr = ma_IActivateAudioInterfaceAsyncOperation_GetActivateResult(pAsyncOp, &activateResult, &pActivatedInterface);
    ma_IActivateAudioInterfaceAsyncOperation_Release(pAsyncOp);

    if (FAILED(hr) || FAILED(activateResult)) {
        ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to activate device.");
        return FAILED(hr) ? ma_result_from_HRESULT(hr) : ma_result_from_HRESULT(activateResult);
    }

    /* Here is where we grab the IAudioClient interface. */
    hr = ma_IUnknown_QueryInterface(pActivatedInterface, &MA_IID_IAudioClient, (void**)ppAudioClient);
    if (FAILED(hr)) {
        ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to query IAudioClient interface.");
        return ma_result_from_HRESULT(hr);
    }

    if (ppActivatedInterface) {
        *ppActivatedInterface = pActivatedInterface;
    } else {
        ma_IUnknown_Release(pActivatedInterface);
    }

    return MA_SUCCESS;
}
#endif

static ma_result ma_context_get_IAudioClient__wasapi(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_IAudioClient** ppAudioClient, ma_WASAPIDeviceInterface** ppDeviceInterface)
{
#if defined(MA_WIN32_DESKTOP) || defined(MA_WIN32_GDK)
    return ma_context_get_IAudioClient_Desktop__wasapi(pContext, deviceType, pDeviceID, ppAudioClient, ppDeviceInterface);
#else
    return ma_context_get_IAudioClient_UWP__wasapi(pContext, deviceType, pDeviceID, ppAudioClient, ppDeviceInterface);
#endif
}


static ma_result ma_context_enumerate_devices__wasapi(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData)
{
    /* Different enumeration for desktop and UWP. */
#if defined(MA_WIN32_DESKTOP) || defined(MA_WIN32_GDK)
    /* Desktop */
    HRESULT hr;
    ma_IMMDeviceEnumerator* pDeviceEnumerator;

    hr = ma_CoCreateInstance(pContext, MA_CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, MA_IID_IMMDeviceEnumerator, (void**)&pDeviceEnumerator);
    if (FAILED(hr)) {
        ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to create device enumerator.");
        return ma_result_from_HRESULT(hr);
    }

    ma_context_enumerate_devices_by_type__wasapi(pContext, pDeviceEnumerator, ma_device_type_playback, callback, pUserData);
    ma_context_enumerate_devices_by_type__wasapi(pContext, pDeviceEnumerator, ma_device_type_capture,  callback, pUserData);

    ma_IMMDeviceEnumerator_Release(pDeviceEnumerator);
#else
    /*
    UWP

    The MMDevice API is only supported on desktop applications. For now, while I'm still figuring out how to properly enumerate
    over devices without using MMDevice, I'm restricting devices to defaults.

    Hint: DeviceInformation::FindAllAsync() with DeviceClass.AudioCapture/AudioRender. https://blogs.windows.com/buildingapps/2014/05/15/real-time-audio-in-windows-store-and-windows-phone-apps/
    */
    if (callback) {
        ma_bool32 cbResult = MA_TRUE;

        /* Playback. */
        if (cbResult) {
            ma_device_info deviceInfo;
            MA_ZERO_OBJECT(&deviceInfo);
            ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1);
            deviceInfo.isDefault = MA_TRUE;
            cbResult = callback(pContext, ma_device_type_playback, &deviceInfo, pUserData);
        }

        /* Capture. */
        if (cbResult) {
            ma_device_info deviceInfo;
            MA_ZERO_OBJECT(&deviceInfo);
            ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1);
            deviceInfo.isDefault = MA_TRUE;
            cbResult = callback(pContext, ma_device_type_capture, &deviceInfo, pUserData);
        }
    }
#endif

    return MA_SUCCESS;
}

static ma_result ma_context_get_device_info__wasapi(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_device_info* pDeviceInfo)
{
#if defined(MA_WIN32_DESKTOP) || defined(MA_WIN32_GDK)
    ma_result result;
    ma_IMMDevice* pMMDevice = NULL;
    LPWSTR pDefaultDeviceID = NULL;

    result = ma_context_get_MMDevice__wasapi(pContext, deviceType, pDeviceID, &pMMDevice);
    if (result != MA_SUCCESS) {
        return result;
    }

    /* We need the default device ID so we can set the isDefault flag in the device info. */
    pDefaultDeviceID = ma_context_get_default_device_id__wasapi(pContext, deviceType);

    result = ma_context_get_device_info_from_MMDevice__wasapi(pContext, pMMDevice, pDefaultDeviceID, MA_FALSE, pDeviceInfo);   /* MA_FALSE = !onlySimpleInfo. */

    if (pDefaultDeviceID != NULL) {
        ma_CoTaskMemFree(pContext, pDefaultDeviceID);
        pDefaultDeviceID = NULL;
    }

    ma_IMMDevice_Release(pMMDevice);

    return result;
#else
    ma_IAudioClient* pAudioClient;
    ma_result result;

    /* UWP currently only uses default devices. */

miniaudio/miniaudio.h  view on Meta::CPAN

    MA_REFERENCE_TIME periodDurationInMicroseconds;
    ma_bool32 wasInitializedUsingIAudioClient3 = MA_FALSE;
    WAVEFORMATEXTENSIBLE wf;
    ma_WASAPIDeviceInterface* pDeviceInterface = NULL;
    ma_IAudioClient2* pAudioClient2;
    ma_uint32 nativeSampleRate;

    MA_ASSERT(pContext != NULL);
    MA_ASSERT(pData != NULL);

    /* This function is only used to initialize one device type: either playback, capture or loopback. Never full-duplex. */
    if (deviceType == ma_device_type_duplex) {
        return MA_INVALID_ARGS;
    }

    pData->pAudioClient = NULL;
    pData->pRenderClient = NULL;
    pData->pCaptureClient = NULL;

    streamFlags = MA_AUDCLNT_STREAMFLAGS_EVENTCALLBACK;
    if (!pData->noAutoConvertSRC && pData->sampleRateIn != 0 && pData->shareMode != ma_share_mode_exclusive) {    /* <-- Exclusive streams must use the native sample rate. */
        streamFlags |= MA_AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM;
    }
    if (!pData->noDefaultQualitySRC && pData->sampleRateIn != 0 && (streamFlags & MA_AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM) != 0) {
        streamFlags |= MA_AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY;
    }
    if (deviceType == ma_device_type_loopback) {
        streamFlags |= MA_AUDCLNT_STREAMFLAGS_LOOPBACK;
    }

    result = ma_context_get_IAudioClient__wasapi(pContext, deviceType, pDeviceID, &pData->pAudioClient, &pDeviceInterface);
    if (result != MA_SUCCESS) {
        goto done;
    }

    MA_ZERO_OBJECT(&wf);

    /* Try enabling hardware offloading. */
    if (!pData->noHardwareOffloading) {
        hr = ma_IAudioClient_QueryInterface(pData->pAudioClient, &MA_IID_IAudioClient2, (void**)&pAudioClient2);
        if (SUCCEEDED(hr)) {
            BOOL isHardwareOffloadingSupported = 0;
            hr = ma_IAudioClient2_IsOffloadCapable(pAudioClient2, MA_AudioCategory_Other, &isHardwareOffloadingSupported);
            if (SUCCEEDED(hr) && isHardwareOffloadingSupported) {
                ma_AudioClientProperties clientProperties;
                MA_ZERO_OBJECT(&clientProperties);
                clientProperties.cbSize = sizeof(clientProperties);
                clientProperties.bIsOffload = 1;
                clientProperties.eCategory = MA_AudioCategory_Other;
                ma_IAudioClient2_SetClientProperties(pAudioClient2, &clientProperties);
            }

            pAudioClient2->lpVtbl->Release(pAudioClient2);
        }
    }

    /* Here is where we try to determine the best format to use with the device. If the client if wanting exclusive mode, first try finding the best format for that. If this fails, fall back to shared mode. */
    result = MA_FORMAT_NOT_SUPPORTED;
    if (pData->shareMode == ma_share_mode_exclusive) {
    #if defined(MA_WIN32_DESKTOP) || defined(MA_WIN32_GDK)
        /* In exclusive mode on desktop we always use the backend's native format. */
        ma_IPropertyStore* pStore = NULL;
        hr = ma_IMMDevice_OpenPropertyStore(pDeviceInterface, STGM_READ, &pStore);
        if (SUCCEEDED(hr)) {
            PROPVARIANT prop;
            ma_PropVariantInit(&prop);
            hr = ma_IPropertyStore_GetValue(pStore, &MA_PKEY_AudioEngine_DeviceFormat, &prop);
            if (SUCCEEDED(hr)) {
                WAVEFORMATEX* pActualFormat = (WAVEFORMATEX*)prop.blob.pBlobData;
                hr = ma_IAudioClient_IsFormatSupported((ma_IAudioClient*)pData->pAudioClient, MA_AUDCLNT_SHAREMODE_EXCLUSIVE, pActualFormat, NULL);
                if (SUCCEEDED(hr)) {
                    MA_COPY_MEMORY(&wf, pActualFormat, sizeof(WAVEFORMATEXTENSIBLE));
                }

                ma_PropVariantClear(pContext, &prop);
            }

            ma_IPropertyStore_Release(pStore);
        }
    #else
        /*
        I do not know how to query the device's native format on UWP so for now I'm just disabling support for
        exclusive mode. The alternative is to enumerate over different formats and check IsFormatSupported()
        until you find one that works.

        TODO: Add support for exclusive mode to UWP.
        */
        hr = S_FALSE;
    #endif

        if (hr == S_OK) {
            shareMode = MA_AUDCLNT_SHAREMODE_EXCLUSIVE;
            result = MA_SUCCESS;
        } else {
            result = MA_SHARE_MODE_NOT_SUPPORTED;
        }
    } else {
        /* In shared mode we are always using the format reported by the operating system. */
        WAVEFORMATEXTENSIBLE* pNativeFormat = NULL;
        hr = ma_IAudioClient_GetMixFormat((ma_IAudioClient*)pData->pAudioClient, (WAVEFORMATEX**)&pNativeFormat);
        if (hr != S_OK) {
            result = MA_FORMAT_NOT_SUPPORTED;
        } else {
            MA_COPY_MEMORY(&wf, pNativeFormat, sizeof(wf));
            result = MA_SUCCESS;
        }

        ma_CoTaskMemFree(pContext, pNativeFormat);

        shareMode = MA_AUDCLNT_SHAREMODE_SHARED;
    }

    /* Return an error if we still haven't found a format. */
    if (result != MA_SUCCESS) {
        errorMsg = "[WASAPI] Failed to find best device mix format.";
        goto done;
    }

    /*
    Override the native sample rate with the one requested by the caller, but only if we're not using the default sample rate. We'll use
    WASAPI to perform the sample rate conversion.

miniaudio/miniaudio.h  view on Meta::CPAN

                }

                ma_free(pSampleRateRanges, &pContext->allocationCallbacks);

                if (pDeviceInfo->nativeDataFormatCount >= ma_countof(pDeviceInfo->nativeDataFormats)) {
                    break;  /* No more room for any more formats. */
                }
            }

            ma_free(pStreamDescriptions, &pContext->allocationCallbacks);
        }
    }
#else
    /* Mobile */
    {
        AudioComponentDescription desc;
        AudioComponent component;
        AudioUnit audioUnit;
        OSStatus status;
        AudioUnitScope formatScope;
        AudioUnitElement formatElement;
        AudioStreamBasicDescription bestFormat;
        UInt32 propSize;

        /* We want to ensure we use a consistent device name to device enumeration. */
        if (pDeviceID != NULL && pDeviceID->coreaudio[0] != '\0') {
            ma_bool32 found = MA_FALSE;
            if (deviceType == ma_device_type_playback) {
                NSArray *pOutputs = [[[AVAudioSession sharedInstance] currentRoute] outputs];
                for (AVAudioSessionPortDescription* pPortDesc in pOutputs) {
                    if (strcmp(pDeviceID->coreaudio, [pPortDesc.UID UTF8String]) == 0) {
                        ma_AVAudioSessionPortDescription_to_device_info(pPortDesc, pDeviceInfo);
                        found = MA_TRUE;
                        break;
                    }
                }
            } else {
                NSArray *pInputs = [[[AVAudioSession sharedInstance] currentRoute] inputs];
                for (AVAudioSessionPortDescription* pPortDesc in pInputs) {
                    if (strcmp(pDeviceID->coreaudio, [pPortDesc.UID UTF8String]) == 0) {
                        ma_AVAudioSessionPortDescription_to_device_info(pPortDesc, pDeviceInfo);
                        found = MA_TRUE;
                        break;
                    }
                }
            }

            if (!found) {
                return MA_DOES_NOT_EXIST;
            }
        } else {
            if (deviceType == ma_device_type_playback) {
                ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1);
            } else {
                ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1);
            }
        }


        /*
        Retrieving device information is more annoying on mobile than desktop. For simplicity I'm locking this down to whatever format is
        reported on a temporary I/O unit. The problem, however, is that this doesn't return a value for the sample rate which we need to
        retrieve from the AVAudioSession shared instance.
        */
        desc.componentType = kAudioUnitType_Output;
        desc.componentSubType = kAudioUnitSubType_RemoteIO;
        desc.componentManufacturer = kAudioUnitManufacturer_Apple;
        desc.componentFlags = 0;
        desc.componentFlagsMask = 0;

        component = ((ma_AudioComponentFindNext_proc)pContext->coreaudio.AudioComponentFindNext)(NULL, &desc);
        if (component == NULL) {
            return MA_FAILED_TO_INIT_BACKEND;
        }

        status = ((ma_AudioComponentInstanceNew_proc)pContext->coreaudio.AudioComponentInstanceNew)(component, &audioUnit);
        if (status != noErr) {
            return ma_result_from_OSStatus(status);
        }

        formatScope   = (deviceType == ma_device_type_playback) ? kAudioUnitScope_Input : kAudioUnitScope_Output;
        formatElement = (deviceType == ma_device_type_playback) ? MA_COREAUDIO_OUTPUT_BUS : MA_COREAUDIO_INPUT_BUS;

        propSize = sizeof(bestFormat);
        status = ((ma_AudioUnitGetProperty_proc)pContext->coreaudio.AudioUnitGetProperty)(audioUnit, kAudioUnitProperty_StreamFormat, formatScope, formatElement, &bestFormat, &propSize);
        if (status != noErr) {
            ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(audioUnit);
            return ma_result_from_OSStatus(status);
        }

        ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(audioUnit);
        audioUnit = NULL;

        /* Only a single format is being reported for iOS. */
        pDeviceInfo->nativeDataFormatCount = 1;

        result = ma_format_from_AudioStreamBasicDescription(&bestFormat, &pDeviceInfo->nativeDataFormats[0].format);
        if (result != MA_SUCCESS) {
            return result;
        }

        pDeviceInfo->nativeDataFormats[0].channels = bestFormat.mChannelsPerFrame;

        /*
        It looks like Apple are wanting to push the whole AVAudioSession thing. Thus, we need to use that to determine device settings. To do
        this we just get the shared instance and inspect.
        */
        @autoreleasepool {
            AVAudioSession* pAudioSession = [AVAudioSession sharedInstance];
            MA_ASSERT(pAudioSession != NULL);

            pDeviceInfo->nativeDataFormats[0].sampleRate = (ma_uint32)pAudioSession.sampleRate;
        }
    }
#endif

    (void)pDeviceInfo; /* Unused. */
    return MA_SUCCESS;
}

static AudioBufferList* ma_allocate_AudioBufferList__coreaudio(ma_uint32 sizeInFrames, ma_format format, ma_uint32 channels, ma_stream_layout layout, const ma_allocation_callbacks* pAllocationCallbacks)

miniaudio/miniaudio.h  view on Meta::CPAN

    if (deviceType == ma_device_type_duplex) {
        return MA_INVALID_ARGS;
    }

    MA_ASSERT(pContext != NULL);
    MA_ASSERT(deviceType == ma_device_type_playback || deviceType == ma_device_type_capture);

#if defined(MA_APPLE_DESKTOP)
    pData->deviceObjectID = 0;
#endif
    pData->component = NULL;
    pData->audioUnit = NULL;
    pData->pAudioBufferList = NULL;

#if defined(MA_APPLE_DESKTOP)
    result = ma_find_AudioObjectID(pContext, deviceType, pDeviceID, &deviceObjectID);
    if (result != MA_SUCCESS) {
        return result;
    }

    pData->deviceObjectID = deviceObjectID;
#endif

    /* Core audio doesn't really use the notion of a period so we can leave this unmodified, but not too over the top. */
    pData->periodsOut = pData->periodsIn;
    if (pData->periodsOut == 0) {
        pData->periodsOut = MA_DEFAULT_PERIODS;
    }
    if (pData->periodsOut > 16) {
        pData->periodsOut = 16;
    }


    /* Audio unit. */
    status = ((ma_AudioComponentInstanceNew_proc)pContext->coreaudio.AudioComponentInstanceNew)((AudioComponent)pContext->coreaudio.component, (AudioUnit*)&pData->audioUnit);
    if (status != noErr) {
        return ma_result_from_OSStatus(status);
    }


    /* The input/output buses need to be explicitly enabled and disabled. We set the flag based on the output unit first, then we just swap it for input. */
    enableIOFlag = 1;
    if (deviceType == ma_device_type_capture) {
        enableIOFlag = 0;
    }

    status = ((ma_AudioUnitSetProperty_proc)pContext->coreaudio.AudioUnitSetProperty)(pData->audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, MA_COREAUDIO_OUTPUT_BUS, &enableIOFlag, sizeof(enableIOFlag));
    if (status != noErr) {
        ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
        return ma_result_from_OSStatus(status);
    }

    enableIOFlag = (enableIOFlag == 0) ? 1 : 0;
    status = ((ma_AudioUnitSetProperty_proc)pContext->coreaudio.AudioUnitSetProperty)(pData->audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, MA_COREAUDIO_INPUT_BUS, &enableIOFlag, sizeof(enableIOFlag));
    if (status != noErr) {
        ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
        return ma_result_from_OSStatus(status);
    }


    /* Set the device to use with this audio unit. This is only used on desktop since we are using defaults on mobile. */
#if defined(MA_APPLE_DESKTOP)
    status = ((ma_AudioUnitSetProperty_proc)pContext->coreaudio.AudioUnitSetProperty)(pData->audioUnit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &deviceObjectID, sizeof(deviceObjectID));
    if (status != noErr) {
        ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
        return ma_result_from_OSStatus(result);
    }
#else
    /*
    For some reason it looks like Apple is only allowing selection of the input device. There does not appear to be any way to change
    the default output route. I have no idea why this is like this, but for now we'll only be able to configure capture devices.
    */
    if (pDeviceID != NULL) {
        if (deviceType == ma_device_type_capture) {
            ma_bool32 found = MA_FALSE;
            NSArray *pInputs = [[[AVAudioSession sharedInstance] currentRoute] inputs];
            for (AVAudioSessionPortDescription* pPortDesc in pInputs) {
                if (strcmp(pDeviceID->coreaudio, [pPortDesc.UID UTF8String]) == 0) {
                    [[AVAudioSession sharedInstance] setPreferredInput:pPortDesc error:nil];
                    found = MA_TRUE;
                    break;
                }
            }

            if (found == MA_FALSE) {
                return MA_DOES_NOT_EXIST;
            }
        }
    }
#endif

    /*
    Format. This is the hardest part of initialization because there's a few variables to take into account.
      1) The format must be supported by the device.
      2) The format must be supported miniaudio.
      3) There's a priority that miniaudio prefers.

    Ideally we would like to use a format that's as close to the hardware as possible so we can get as close to a passthrough as possible. The
    most important property is the sample rate. miniaudio can do format conversion for any sample rate and channel count, but cannot do the same
    for the sample data format. If the sample data format is not supported by miniaudio it must be ignored completely.

    On mobile platforms this is a bit different. We just force the use of whatever the audio unit's current format is set to.
    */
    {
        AudioStreamBasicDescription origFormat;
        UInt32 origFormatSize = sizeof(origFormat);
        AudioUnitScope   formatScope   = (deviceType == ma_device_type_playback) ? kAudioUnitScope_Input : kAudioUnitScope_Output;
        AudioUnitElement formatElement = (deviceType == ma_device_type_playback) ? MA_COREAUDIO_OUTPUT_BUS : MA_COREAUDIO_INPUT_BUS;

        if (deviceType == ma_device_type_playback) {
            status = ((ma_AudioUnitGetProperty_proc)pContext->coreaudio.AudioUnitGetProperty)(pData->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, MA_COREAUDIO_OUTPUT_BUS, &origFormat, &origFormatSize);
        } else {
            status = ((ma_AudioUnitGetProperty_proc)pContext->coreaudio.AudioUnitGetProperty)(pData->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, MA_COREAUDIO_INPUT_BUS, &origFormat, &origFormatSize);
        }
        if (status != noErr) {
            ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
            return ma_result_from_OSStatus(status);
        }

    #if defined(MA_APPLE_DESKTOP)
        result = ma_find_best_format__coreaudio(pContext, deviceObjectID, deviceType, pData->formatIn, pData->channelsIn, pData->sampleRateIn, &origFormat, &bestFormat);



( run in 3.125 seconds using v1.01-cache-2.11-cpan-2c0d6866c4f )