mirror of
https://github.com/mackron/miniaudio.git
synced 2026-04-24 01:04:02 +02:00
Merge branch 'dev' of https://github.com/mackron/miniaudio into dev
This commit is contained in:
+208
-213
@@ -2855,7 +2855,7 @@ typedef struct
|
|||||||
ma_pcm_rb rb;
|
ma_pcm_rb rb;
|
||||||
} ma_duplex_rb;
|
} ma_duplex_rb;
|
||||||
|
|
||||||
MA_API ma_result ma_duplex_rb_init(ma_uint32 inputSampleRate, ma_format captureFormat, ma_uint32 captureChannels, ma_uint32 captureSampleRate, ma_uint32 capturePeriodSizeInFrames, const ma_allocation_callbacks* pAllocationCallbacks, ma_duplex_rb* pRB);
|
MA_API ma_result ma_duplex_rb_init(ma_format captureFormat, ma_uint32 captureChannels, ma_uint32 sampleRate, ma_uint32 captureInternalSampleRate, ma_uint32 captureInternalPeriodSizeInFrames, const ma_allocation_callbacks* pAllocationCallbacks, ma_duplex_rb* pRB);
|
||||||
MA_API ma_result ma_duplex_rb_uninit(ma_duplex_rb* pRB);
|
MA_API ma_result ma_duplex_rb_uninit(ma_duplex_rb* pRB);
|
||||||
|
|
||||||
|
|
||||||
@@ -4150,11 +4150,11 @@ struct ma_device
|
|||||||
ma_uint32 originalPeriodSizeInFrames;
|
ma_uint32 originalPeriodSizeInFrames;
|
||||||
ma_uint32 originalPeriodSizeInMilliseconds;
|
ma_uint32 originalPeriodSizeInMilliseconds;
|
||||||
ma_uint32 originalPeriods;
|
ma_uint32 originalPeriods;
|
||||||
|
ma_performance_profile originalPerformanceProfile;
|
||||||
ma_bool32 isDefaultPlaybackDevice;
|
ma_bool32 isDefaultPlaybackDevice;
|
||||||
ma_bool32 isDefaultCaptureDevice;
|
ma_bool32 isDefaultCaptureDevice;
|
||||||
ma_bool32 isSwitchingPlaybackDevice; /* <-- Set to true when the default device has changed and miniaudio is in the process of switching. */
|
ma_bool32 isSwitchingPlaybackDevice; /* <-- Set to true when the default device has changed and miniaudio is in the process of switching. */
|
||||||
ma_bool32 isSwitchingCaptureDevice; /* <-- Set to true when the default device has changed and miniaudio is in the process of switching. */
|
ma_bool32 isSwitchingCaptureDevice; /* <-- Set to true when the default device has changed and miniaudio is in the process of switching. */
|
||||||
ma_pcm_rb duplexRB;
|
|
||||||
void* pRouteChangeHandler; /* Only used on mobile platforms. Obj-C object for handling route changes. */
|
void* pRouteChangeHandler; /* Only used on mobile platforms. Obj-C object for handling route changes. */
|
||||||
} coreaudio;
|
} coreaudio;
|
||||||
#endif
|
#endif
|
||||||
@@ -22495,6 +22495,8 @@ static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_confi
|
|||||||
int error = 0;
|
int error = 0;
|
||||||
const char* devPlayback = NULL;
|
const char* devPlayback = NULL;
|
||||||
const char* devCapture = NULL;
|
const char* devCapture = NULL;
|
||||||
|
ma_format format;
|
||||||
|
ma_uint32 channels;
|
||||||
ma_uint32 sampleRate;
|
ma_uint32 sampleRate;
|
||||||
ma_pa_sink_info sinkInfo;
|
ma_pa_sink_info sinkInfo;
|
||||||
ma_pa_source_info sourceInfo;
|
ma_pa_source_info sourceInfo;
|
||||||
@@ -22525,6 +22527,8 @@ static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_confi
|
|||||||
devPlayback = pDescriptorPlayback->pDeviceID->pulse;
|
devPlayback = pDescriptorPlayback->pDeviceID->pulse;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
format = pDescriptorPlayback->format;
|
||||||
|
channels = pDescriptorPlayback->channels;
|
||||||
sampleRate = pDescriptorPlayback->sampleRate;
|
sampleRate = pDescriptorPlayback->sampleRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -22533,6 +22537,8 @@ static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_confi
|
|||||||
devCapture = pDescriptorCapture->pDeviceID->pulse;
|
devCapture = pDescriptorCapture->pDeviceID->pulse;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
format = pDescriptorCapture->format;
|
||||||
|
channels = pDescriptorCapture->channels;
|
||||||
sampleRate = pDescriptorCapture->sampleRate;
|
sampleRate = pDescriptorCapture->sampleRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -22742,7 +22748,7 @@ static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_confi
|
|||||||
onDeviceAudioThread callback is NULL, which is not the case for PulseAudio.
|
onDeviceAudioThread callback is NULL, which is not the case for PulseAudio.
|
||||||
*/
|
*/
|
||||||
if (pConfig->deviceType == ma_device_type_duplex) {
|
if (pConfig->deviceType == ma_device_type_duplex) {
|
||||||
result = ma_duplex_rb_init(sampleRate, pDescriptorCapture->format, pDescriptorCapture->channels, pDescriptorCapture->sampleRate, pDescriptorCapture->periodSizeInFrames, &pDevice->pContext->allocationCallbacks, &pDevice->duplexRB);
|
result = ma_duplex_rb_init(format, channels, sampleRate, pDescriptorCapture->sampleRate, pDescriptorCapture->periodSizeInFrames, &pDevice->pContext->allocationCallbacks, &pDevice->duplexRB);
|
||||||
if (result != MA_SUCCESS) {
|
if (result != MA_SUCCESS) {
|
||||||
result = ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to initialize ring buffer.", result);
|
result = ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to initialize ring buffer.", result);
|
||||||
goto on_error4;
|
goto on_error4;
|
||||||
@@ -24786,7 +24792,7 @@ static ma_result ma_find_AudioObjectID(ma_context* pContext, ma_device_type devi
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static ma_result ma_find_best_format__coreaudio(ma_context* pContext, AudioObjectID deviceObjectID, ma_device_type deviceType, ma_format format, ma_uint32 channels, ma_uint32 sampleRate, ma_bool32 usingDefaultFormat, ma_bool32 usingDefaultChannels, ma_bool32 usingDefaultSampleRate, const AudioStreamBasicDescription* pOrigFormat, AudioStreamBasicDescription* pFormat)
|
static ma_result ma_find_best_format__coreaudio(ma_context* pContext, AudioObjectID deviceObjectID, ma_device_type deviceType, ma_format format, ma_uint32 channels, ma_uint32 sampleRate, const AudioStreamBasicDescription* pOrigFormat, AudioStreamBasicDescription* pFormat)
|
||||||
{
|
{
|
||||||
UInt32 deviceFormatDescriptionCount;
|
UInt32 deviceFormatDescriptionCount;
|
||||||
AudioStreamRangedDescription* pDeviceFormatDescriptions;
|
AudioStreamRangedDescription* pDeviceFormatDescriptions;
|
||||||
@@ -24804,17 +24810,17 @@ static ma_result ma_find_best_format__coreaudio(ma_context* pContext, AudioObjec
|
|||||||
}
|
}
|
||||||
|
|
||||||
desiredSampleRate = sampleRate;
|
desiredSampleRate = sampleRate;
|
||||||
if (usingDefaultSampleRate) {
|
if (desiredSampleRate == 0) {
|
||||||
desiredSampleRate = pOrigFormat->mSampleRate;
|
desiredSampleRate = pOrigFormat->mSampleRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
desiredChannelCount = channels;
|
desiredChannelCount = channels;
|
||||||
if (usingDefaultChannels) {
|
if (desiredChannelCount == 0) {
|
||||||
desiredChannelCount = pOrigFormat->mChannelsPerFrame;
|
desiredChannelCount = pOrigFormat->mChannelsPerFrame;
|
||||||
}
|
}
|
||||||
|
|
||||||
desiredFormat = format;
|
desiredFormat = format;
|
||||||
if (usingDefaultFormat) {
|
if (desiredFormat == ma_format_unknown) {
|
||||||
result = ma_format_from_AudioStreamBasicDescription(pOrigFormat, &desiredFormat);
|
result = ma_format_from_AudioStreamBasicDescription(pOrigFormat, &desiredFormat);
|
||||||
if (result != MA_SUCCESS || desiredFormat == ma_format_unknown) {
|
if (result != MA_SUCCESS || desiredFormat == ma_format_unknown) {
|
||||||
desiredFormat = g_maFormatPriorities[0];
|
desiredFormat = g_maFormatPriorities[0];
|
||||||
@@ -25096,17 +25102,12 @@ static ma_result ma_context_enumerate_devices__coreaudio(ma_context* pContext, m
|
|||||||
return MA_SUCCESS;
|
return MA_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ma_result ma_context_get_device_info__coreaudio(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_share_mode shareMode, ma_device_info* pDeviceInfo)
|
static ma_result ma_context_get_device_info__coreaudio(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_device_info* pDeviceInfo)
|
||||||
{
|
{
|
||||||
ma_result result;
|
ma_result result;
|
||||||
|
|
||||||
MA_ASSERT(pContext != NULL);
|
MA_ASSERT(pContext != NULL);
|
||||||
|
|
||||||
/* No exclusive mode with the Core Audio backend for now. */
|
|
||||||
if (shareMode == ma_share_mode_exclusive) {
|
|
||||||
return MA_SHARE_MODE_NOT_SUPPORTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(MA_APPLE_DESKTOP)
|
#if defined(MA_APPLE_DESKTOP)
|
||||||
/* Desktop */
|
/* Desktop */
|
||||||
{
|
{
|
||||||
@@ -25139,66 +25140,98 @@ static ma_result ma_context_get_device_info__coreaudio(ma_context* pContext, ma_
|
|||||||
pDeviceInfo->isDefault = MA_TRUE;
|
pDeviceInfo->isDefault = MA_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
There could be a large number of permutations here. Fortunately there is only a single channel count
|
||||||
|
being reported which reduces this quite a bit. For sample rates we're only reporting those that are
|
||||||
|
one of miniaudio's recognized "standard" rates. If there are still more formats than can fit into
|
||||||
|
our fixed sized array we'll just need to truncate them. This is unlikely and will probably only happen
|
||||||
|
if some driver performs software data conversion and therefore reports every possible format and
|
||||||
|
sample rate.
|
||||||
|
*/
|
||||||
|
pDeviceInfo->nativeDataFormatCount = 0;
|
||||||
|
|
||||||
/* Formats. */
|
/* Formats. */
|
||||||
result = ma_get_AudioObject_stream_descriptions(pContext, deviceObjectID, deviceType, &streamDescriptionCount, &pStreamDescriptions);
|
{
|
||||||
if (result != MA_SUCCESS) {
|
ma_format uniqueFormats[ma_format_count];
|
||||||
return result;
|
ma_uint32 uniqueFormatCount = 0;
|
||||||
}
|
ma_uint32 channels;
|
||||||
|
|
||||||
for (iStreamDescription = 0; iStreamDescription < streamDescriptionCount; ++iStreamDescription) {
|
/* Channels. */
|
||||||
ma_format format;
|
result = ma_get_AudioObject_channel_count(pContext, deviceObjectID, deviceType, &channels);
|
||||||
ma_bool32 formatExists = MA_FALSE;
|
|
||||||
ma_uint32 iOutputFormat;
|
|
||||||
|
|
||||||
result = ma_format_from_AudioStreamBasicDescription(&pStreamDescriptions[iStreamDescription].mFormat, &format);
|
|
||||||
if (result != MA_SUCCESS) {
|
if (result != MA_SUCCESS) {
|
||||||
continue;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
MA_ASSERT(format != ma_format_unknown);
|
/* Formats. */
|
||||||
|
result = ma_get_AudioObject_stream_descriptions(pContext, deviceObjectID, deviceType, &streamDescriptionCount, &pStreamDescriptions);
|
||||||
|
if (result != MA_SUCCESS) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/* Make sure the format isn't already in the output list. */
|
for (iStreamDescription = 0; iStreamDescription < streamDescriptionCount; ++iStreamDescription) {
|
||||||
for (iOutputFormat = 0; iOutputFormat < pDeviceInfo->formatCount; ++iOutputFormat) {
|
ma_format format;
|
||||||
if (pDeviceInfo->formats[iOutputFormat] == format) {
|
ma_bool32 hasFormatBeenHandled = MA_FALSE;
|
||||||
formatExists = MA_TRUE;
|
ma_uint32 iOutputFormat;
|
||||||
break;
|
ma_uint32 iSampleRate;
|
||||||
|
|
||||||
|
result = ma_format_from_AudioStreamBasicDescription(&pStreamDescriptions[iStreamDescription].mFormat, &format);
|
||||||
|
if (result != MA_SUCCESS) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
MA_ASSERT(format != ma_format_unknown);
|
||||||
|
|
||||||
|
/* Make sure the format isn't already in the output list. */
|
||||||
|
for (iOutputFormat = 0; iOutputFormat < uniqueFormatCount; ++iOutputFormat) {
|
||||||
|
if (uniqueFormats[iOutputFormat] == format) {
|
||||||
|
hasFormatBeenHandled = MA_TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we've already handled this format just skip it. */
|
||||||
|
if (hasFormatBeenHandled) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
uniqueFormatCount += 1;
|
||||||
|
|
||||||
|
|
||||||
|
/* Sample Rates */
|
||||||
|
result = ma_get_AudioObject_sample_rates(pContext, deviceObjectID, deviceType, &sampleRateRangeCount, &pSampleRateRanges);
|
||||||
|
if (result != MA_SUCCESS) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Annoyingly Core Audio reports a sample rate range. We just get all the standard rates that are
|
||||||
|
between this range.
|
||||||
|
*/
|
||||||
|
for (iSampleRate = 0; iSampleRate < sampleRateRangeCount; ++iSampleRate) {
|
||||||
|
ma_uint32 iStandardSampleRate;
|
||||||
|
for (iStandardSampleRate = 0; iStandardSampleRate < ma_countof(g_maStandardSampleRatePriorities); iStandardSampleRate += 1) {
|
||||||
|
ma_uint32 standardSampleRate = g_maStandardSampleRatePriorities[iStandardSampleRate];
|
||||||
|
if (standardSampleRate >= pSampleRateRanges[iSampleRate].mMinimum && standardSampleRate <= pSampleRateRanges[iSampleRate].mMaximum) {
|
||||||
|
/* We have a new data format. Add it to the list. */
|
||||||
|
pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].format = format;
|
||||||
|
pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].channels = channels;
|
||||||
|
pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].sampleRate = standardSampleRate;
|
||||||
|
pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].flags = 0;
|
||||||
|
pDeviceInfo->nativeDataFormatCount += 1;
|
||||||
|
|
||||||
|
if (pDeviceInfo->nativeDataFormatCount >= ma_countof(pDeviceInfo->nativeDataFormats)) {
|
||||||
|
break; /* No more room for any more formats. */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pDeviceInfo->nativeDataFormatCount >= ma_countof(pDeviceInfo->nativeDataFormats)) {
|
||||||
|
break; /* No more room for any more formats. */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!formatExists) {
|
ma_free(pStreamDescriptions, &pContext->allocationCallbacks);
|
||||||
pDeviceInfo->formats[pDeviceInfo->formatCount++] = format;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ma_free(pStreamDescriptions, &pContext->allocationCallbacks);
|
|
||||||
|
|
||||||
|
|
||||||
/* Channels. */
|
|
||||||
result = ma_get_AudioObject_channel_count(pContext, deviceObjectID, deviceType, &pDeviceInfo->minChannels);
|
|
||||||
if (result != MA_SUCCESS) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
pDeviceInfo->maxChannels = pDeviceInfo->minChannels;
|
|
||||||
|
|
||||||
|
|
||||||
/* Sample rates. */
|
|
||||||
result = ma_get_AudioObject_sample_rates(pContext, deviceObjectID, deviceType, &sampleRateRangeCount, &pSampleRateRanges);
|
|
||||||
if (result != MA_SUCCESS) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sampleRateRangeCount > 0) {
|
|
||||||
UInt32 iSampleRate;
|
|
||||||
pDeviceInfo->minSampleRate = UINT32_MAX;
|
|
||||||
pDeviceInfo->maxSampleRate = 0;
|
|
||||||
for (iSampleRate = 0; iSampleRate < sampleRateRangeCount; ++iSampleRate) {
|
|
||||||
if (pDeviceInfo->minSampleRate > pSampleRateRanges[iSampleRate].mMinimum) {
|
|
||||||
pDeviceInfo->minSampleRate = pSampleRateRanges[iSampleRate].mMinimum;
|
|
||||||
}
|
|
||||||
if (pDeviceInfo->maxSampleRate < pSampleRateRanges[iSampleRate].mMaximum) {
|
|
||||||
pDeviceInfo->maxSampleRate = pSampleRateRanges[iSampleRate].mMaximum;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
@@ -25282,16 +25315,16 @@ static ma_result ma_context_get_device_info__coreaudio(ma_context* pContext, ma_
|
|||||||
((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(audioUnit);
|
((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(audioUnit);
|
||||||
audioUnit = NULL;
|
audioUnit = NULL;
|
||||||
|
|
||||||
|
/* Only a single format is being reported for iOS. */
|
||||||
|
pDeviceInfo->nativeDataFormatCount = 1;
|
||||||
|
|
||||||
pDeviceInfo->minChannels = bestFormat.mChannelsPerFrame;
|
result = ma_format_from_AudioStreamBasicDescription(&bestFormat, &pDeviceInfo->nativeDataFormats[0].format);
|
||||||
pDeviceInfo->maxChannels = bestFormat.mChannelsPerFrame;
|
|
||||||
|
|
||||||
pDeviceInfo->formatCount = 1;
|
|
||||||
result = ma_format_from_AudioStreamBasicDescription(&bestFormat, &pDeviceInfo->formats[0]);
|
|
||||||
if (result != MA_SUCCESS) {
|
if (result != MA_SUCCESS) {
|
||||||
return result;
|
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
|
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.
|
this we just get the shared instance and inspect.
|
||||||
@@ -25300,8 +25333,7 @@ static ma_result ma_context_get_device_info__coreaudio(ma_context* pContext, ma_
|
|||||||
AVAudioSession* pAudioSession = [AVAudioSession sharedInstance];
|
AVAudioSession* pAudioSession = [AVAudioSession sharedInstance];
|
||||||
MA_ASSERT(pAudioSession != NULL);
|
MA_ASSERT(pAudioSession != NULL);
|
||||||
|
|
||||||
pDeviceInfo->minSampleRate = (ma_uint32)pAudioSession.sampleRate;
|
pDeviceInfo->nativeDataFormats[0].sampleRate = (ma_uint32)pAudioSession.sampleRate;
|
||||||
pDeviceInfo->maxSampleRate = pDeviceInfo->minSampleRate;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -25406,11 +25438,7 @@ static OSStatus ma_on_output__coreaudio(void* pUserData, AudioUnitRenderActionFl
|
|||||||
if (pBufferList->mBuffers[iBuffer].mNumberChannels == pDevice->playback.internalChannels) {
|
if (pBufferList->mBuffers[iBuffer].mNumberChannels == pDevice->playback.internalChannels) {
|
||||||
ma_uint32 frameCountForThisBuffer = pBufferList->mBuffers[iBuffer].mDataByteSize / ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels);
|
ma_uint32 frameCountForThisBuffer = pBufferList->mBuffers[iBuffer].mDataByteSize / ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels);
|
||||||
if (frameCountForThisBuffer > 0) {
|
if (frameCountForThisBuffer > 0) {
|
||||||
if (pDevice->type == ma_device_type_duplex) {
|
ma_device_handle_backend_data_callback(pDevice, pBufferList->mBuffers[iBuffer].mData, NULL, frameCountForThisBuffer);
|
||||||
ma_device__handle_duplex_callback_playback(pDevice, frameCountForThisBuffer, pBufferList->mBuffers[iBuffer].mData, &pDevice->coreaudio.duplexRB);
|
|
||||||
} else {
|
|
||||||
ma_device__read_frames_from_client(pDevice, frameCountForThisBuffer, pBufferList->mBuffers[iBuffer].mData);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(MA_DEBUG_OUTPUT)
|
#if defined(MA_DEBUG_OUTPUT)
|
||||||
@@ -25453,11 +25481,7 @@ static OSStatus ma_on_output__coreaudio(void* pUserData, AudioUnitRenderActionFl
|
|||||||
framesToRead = framesRemaining;
|
framesToRead = framesRemaining;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pDevice->type == ma_device_type_duplex) {
|
ma_device_handle_backend_data_callback(pDevice, tempBuffer, NULL, framesToRead);
|
||||||
ma_device__handle_duplex_callback_playback(pDevice, framesToRead, tempBuffer, &pDevice->coreaudio.duplexRB);
|
|
||||||
} else {
|
|
||||||
ma_device__read_frames_from_client(pDevice, framesToRead, tempBuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (iChannel = 0; iChannel < pDevice->playback.internalChannels; ++iChannel) {
|
for (iChannel = 0; iChannel < pDevice->playback.internalChannels; ++iChannel) {
|
||||||
ppDeinterleavedBuffers[iChannel] = (void*)ma_offset_ptr(pBufferList->mBuffers[iBuffer+iChannel].mData, (frameCountPerBuffer - framesRemaining) * ma_get_bytes_per_sample(pDevice->playback.internalFormat));
|
ppDeinterleavedBuffers[iChannel] = (void*)ma_offset_ptr(pBufferList->mBuffers[iBuffer+iChannel].mData, (frameCountPerBuffer - framesRemaining) * ma_get_bytes_per_sample(pDevice->playback.internalFormat));
|
||||||
@@ -25540,11 +25564,8 @@ static OSStatus ma_on_input__coreaudio(void* pUserData, AudioUnitRenderActionFla
|
|||||||
if (layout == ma_stream_layout_interleaved) {
|
if (layout == ma_stream_layout_interleaved) {
|
||||||
for (iBuffer = 0; iBuffer < pRenderedBufferList->mNumberBuffers; ++iBuffer) {
|
for (iBuffer = 0; iBuffer < pRenderedBufferList->mNumberBuffers; ++iBuffer) {
|
||||||
if (pRenderedBufferList->mBuffers[iBuffer].mNumberChannels == pDevice->capture.internalChannels) {
|
if (pRenderedBufferList->mBuffers[iBuffer].mNumberChannels == pDevice->capture.internalChannels) {
|
||||||
if (pDevice->type == ma_device_type_duplex) {
|
ma_device_handle_backend_data_callback(pDevice, NULL, pRenderedBufferList->mBuffers[iBuffer].mData, frameCount);
|
||||||
ma_device__handle_duplex_callback_capture(pDevice, frameCount, pRenderedBufferList->mBuffers[iBuffer].mData, &pDevice->coreaudio.duplexRB);
|
|
||||||
} else {
|
|
||||||
ma_device__send_frames_to_client(pDevice, frameCount, pRenderedBufferList->mBuffers[iBuffer].mData);
|
|
||||||
}
|
|
||||||
#if defined(MA_DEBUG_OUTPUT)
|
#if defined(MA_DEBUG_OUTPUT)
|
||||||
printf(" mDataByteSize=%d\n", pRenderedBufferList->mBuffers[iBuffer].mDataByteSize);
|
printf(" mDataByteSize=%d\n", pRenderedBufferList->mBuffers[iBuffer].mDataByteSize);
|
||||||
#endif
|
#endif
|
||||||
@@ -25565,11 +25586,7 @@ static OSStatus ma_on_input__coreaudio(void* pUserData, AudioUnitRenderActionFla
|
|||||||
framesToSend = framesRemaining;
|
framesToSend = framesRemaining;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pDevice->type == ma_device_type_duplex) {
|
ma_device_handle_backend_data_callback(pDevice, NULL, silentBuffer, framesToSend);
|
||||||
ma_device__handle_duplex_callback_capture(pDevice, framesToSend, silentBuffer, &pDevice->coreaudio.duplexRB);
|
|
||||||
} else {
|
|
||||||
ma_device__send_frames_to_client(pDevice, framesToSend, silentBuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
framesRemaining -= framesToSend;
|
framesRemaining -= framesToSend;
|
||||||
}
|
}
|
||||||
@@ -25604,12 +25621,7 @@ static OSStatus ma_on_input__coreaudio(void* pUserData, AudioUnitRenderActionFla
|
|||||||
}
|
}
|
||||||
|
|
||||||
ma_interleave_pcm_frames(pDevice->capture.internalFormat, pDevice->capture.internalChannels, framesToSend, (const void**)ppDeinterleavedBuffers, tempBuffer);
|
ma_interleave_pcm_frames(pDevice->capture.internalFormat, pDevice->capture.internalChannels, framesToSend, (const void**)ppDeinterleavedBuffers, tempBuffer);
|
||||||
|
ma_device_handle_backend_data_callback(pDevice, NULL, tempBuffer, framesToSend);
|
||||||
if (pDevice->type == ma_device_type_duplex) {
|
|
||||||
ma_device__handle_duplex_callback_capture(pDevice, framesToSend, tempBuffer, &pDevice->coreaudio.duplexRB);
|
|
||||||
} else {
|
|
||||||
ma_device__send_frames_to_client(pDevice, framesToSend, tempBuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
framesRemaining -= framesToSend;
|
framesRemaining -= framesToSend;
|
||||||
}
|
}
|
||||||
@@ -26013,7 +26025,7 @@ static ma_result ma_device__untrack__coreaudio(ma_device* pDevice)
|
|||||||
@end
|
@end
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void ma_device_uninit__coreaudio(ma_device* pDevice)
|
static ma_result ma_device_uninit__coreaudio(ma_device* pDevice)
|
||||||
{
|
{
|
||||||
MA_ASSERT(pDevice != NULL);
|
MA_ASSERT(pDevice != NULL);
|
||||||
MA_ASSERT(ma_device_get_state(pDevice) == MA_STATE_UNINITIALIZED);
|
MA_ASSERT(ma_device_get_state(pDevice) == MA_STATE_UNINITIALIZED);
|
||||||
@@ -26043,9 +26055,7 @@ static void ma_device_uninit__coreaudio(ma_device* pDevice)
|
|||||||
ma__free_from_callbacks(pDevice->coreaudio.pAudioBufferList, &pDevice->pContext->allocationCallbacks);
|
ma__free_from_callbacks(pDevice->coreaudio.pAudioBufferList, &pDevice->pContext->allocationCallbacks);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pDevice->type == ma_device_type_duplex) {
|
return MA_SUCCESS;
|
||||||
ma_pcm_rb_uninit(&pDevice->coreaudio.duplexRB);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
@@ -26060,11 +26070,8 @@ typedef struct
|
|||||||
ma_uint32 periodSizeInFramesIn;
|
ma_uint32 periodSizeInFramesIn;
|
||||||
ma_uint32 periodSizeInMillisecondsIn;
|
ma_uint32 periodSizeInMillisecondsIn;
|
||||||
ma_uint32 periodsIn;
|
ma_uint32 periodsIn;
|
||||||
ma_bool32 usingDefaultFormat;
|
|
||||||
ma_bool32 usingDefaultChannels;
|
|
||||||
ma_bool32 usingDefaultSampleRate;
|
|
||||||
ma_bool32 usingDefaultChannelMap;
|
|
||||||
ma_share_mode shareMode;
|
ma_share_mode shareMode;
|
||||||
|
ma_performance_profile performanceProfile;
|
||||||
ma_bool32 registerStopEvent;
|
ma_bool32 registerStopEvent;
|
||||||
|
|
||||||
/* Output. */
|
/* Output. */
|
||||||
@@ -26218,7 +26225,7 @@ static ma_result ma_device_init_internal__coreaudio(ma_context* pContext, ma_dev
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if defined(MA_APPLE_DESKTOP)
|
#if defined(MA_APPLE_DESKTOP)
|
||||||
result = ma_find_best_format__coreaudio(pContext, deviceObjectID, deviceType, pData->formatIn, pData->channelsIn, pData->sampleRateIn, pData->usingDefaultFormat, pData->usingDefaultChannels, pData->usingDefaultSampleRate, &origFormat, &bestFormat);
|
result = ma_find_best_format__coreaudio(pContext, deviceObjectID, deviceType, pData->formatIn, pData->channelsIn, pData->sampleRateIn, &origFormat, &bestFormat);
|
||||||
if (result != MA_SUCCESS) {
|
if (result != MA_SUCCESS) {
|
||||||
((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
|
((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
|
||||||
return result;
|
return result;
|
||||||
@@ -26358,13 +26365,21 @@ static ma_result ma_device_init_internal__coreaudio(ma_context* pContext, ma_dev
|
|||||||
|
|
||||||
|
|
||||||
/* Buffer size. Not allowing this to be configurable on iOS. */
|
/* Buffer size. Not allowing this to be configurable on iOS. */
|
||||||
actualPeriodSizeInFrames = pData->periodSizeInFramesIn;
|
if (pData->periodSizeInFramesIn == 0) {
|
||||||
|
if (pData->periodSizeInMillisecondsIn == 0) {
|
||||||
#if defined(MA_APPLE_DESKTOP)
|
if (pData->performanceProfile == ma_performance_profile_low_latency) {
|
||||||
if (actualPeriodSizeInFrames == 0) {
|
actualPeriodSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(MA_DEFAULT_PERIOD_SIZE_IN_MILLISECONDS_LOW_LATENCY, pData->sampleRateOut);
|
||||||
actualPeriodSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(pData->periodSizeInMillisecondsIn, pData->sampleRateOut);
|
} else {
|
||||||
|
actualPeriodSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(MA_DEFAULT_PERIOD_SIZE_IN_MILLISECONDS_CONSERVATIVE, pData->sampleRateOut);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
actualPeriodSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(pData->periodSizeInMillisecondsIn, pData->sampleRateOut);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
actualPeriodSizeInFrames = pData->periodSizeInFramesIn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(MA_APPLE_DESKTOP)
|
||||||
result = ma_set_AudioObject_buffer_size_in_frames(pContext, deviceObjectID, deviceType, &actualPeriodSizeInFrames);
|
result = ma_set_AudioObject_buffer_size_in_frames(pContext, deviceObjectID, deviceType, &actualPeriodSizeInFrames);
|
||||||
if (result != MA_SUCCESS) {
|
if (result != MA_SUCCESS) {
|
||||||
return result;
|
return result;
|
||||||
@@ -26480,11 +26495,8 @@ static ma_result ma_device_reinit_internal__coreaudio(ma_device* pDevice, ma_dev
|
|||||||
data.channelsIn = pDevice->capture.channels;
|
data.channelsIn = pDevice->capture.channels;
|
||||||
data.sampleRateIn = pDevice->sampleRate;
|
data.sampleRateIn = pDevice->sampleRate;
|
||||||
MA_COPY_MEMORY(data.channelMapIn, pDevice->capture.channelMap, sizeof(pDevice->capture.channelMap));
|
MA_COPY_MEMORY(data.channelMapIn, pDevice->capture.channelMap, sizeof(pDevice->capture.channelMap));
|
||||||
data.usingDefaultFormat = pDevice->capture.usingDefaultFormat;
|
|
||||||
data.usingDefaultChannels = pDevice->capture.usingDefaultChannels;
|
|
||||||
data.usingDefaultSampleRate = pDevice->usingDefaultSampleRate;
|
|
||||||
data.usingDefaultChannelMap = pDevice->capture.usingDefaultChannelMap;
|
|
||||||
data.shareMode = pDevice->capture.shareMode;
|
data.shareMode = pDevice->capture.shareMode;
|
||||||
|
data.performanceProfile = pDevice->coreaudio.originalPerformanceProfile;
|
||||||
data.registerStopEvent = MA_TRUE;
|
data.registerStopEvent = MA_TRUE;
|
||||||
|
|
||||||
if (disposePreviousAudioUnit) {
|
if (disposePreviousAudioUnit) {
|
||||||
@@ -26499,11 +26511,8 @@ static ma_result ma_device_reinit_internal__coreaudio(ma_device* pDevice, ma_dev
|
|||||||
data.channelsIn = pDevice->playback.channels;
|
data.channelsIn = pDevice->playback.channels;
|
||||||
data.sampleRateIn = pDevice->sampleRate;
|
data.sampleRateIn = pDevice->sampleRate;
|
||||||
MA_COPY_MEMORY(data.channelMapIn, pDevice->playback.channelMap, sizeof(pDevice->playback.channelMap));
|
MA_COPY_MEMORY(data.channelMapIn, pDevice->playback.channelMap, sizeof(pDevice->playback.channelMap));
|
||||||
data.usingDefaultFormat = pDevice->playback.usingDefaultFormat;
|
|
||||||
data.usingDefaultChannels = pDevice->playback.usingDefaultChannels;
|
|
||||||
data.usingDefaultSampleRate = pDevice->usingDefaultSampleRate;
|
|
||||||
data.usingDefaultChannelMap = pDevice->playback.usingDefaultChannelMap;
|
|
||||||
data.shareMode = pDevice->playback.shareMode;
|
data.shareMode = pDevice->playback.shareMode;
|
||||||
|
data.performanceProfile = pDevice->coreaudio.originalPerformanceProfile;
|
||||||
data.registerStopEvent = (pDevice->type != ma_device_type_duplex);
|
data.registerStopEvent = (pDevice->type != ma_device_type_duplex);
|
||||||
|
|
||||||
if (disposePreviousAudioUnit) {
|
if (disposePreviousAudioUnit) {
|
||||||
@@ -26557,21 +26566,20 @@ static ma_result ma_device_reinit_internal__coreaudio(ma_device* pDevice, ma_dev
|
|||||||
}
|
}
|
||||||
#endif /* MA_APPLE_DESKTOP */
|
#endif /* MA_APPLE_DESKTOP */
|
||||||
|
|
||||||
static ma_result ma_device_init__coreaudio(ma_context* pContext, const ma_device_config* pConfig, ma_device* pDevice)
|
static ma_result ma_device_init__coreaudio(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptorPlayback, ma_device_descriptor* pDescriptorCapture)
|
||||||
{
|
{
|
||||||
ma_result result;
|
ma_result result;
|
||||||
|
|
||||||
MA_ASSERT(pContext != NULL);
|
|
||||||
MA_ASSERT(pConfig != NULL);
|
|
||||||
MA_ASSERT(pDevice != NULL);
|
MA_ASSERT(pDevice != NULL);
|
||||||
|
MA_ASSERT(pConfig != NULL);
|
||||||
|
|
||||||
if (pConfig->deviceType == ma_device_type_loopback) {
|
if (pConfig->deviceType == ma_device_type_loopback) {
|
||||||
return MA_DEVICE_TYPE_NOT_SUPPORTED;
|
return MA_DEVICE_TYPE_NOT_SUPPORTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* No exclusive mode with the Core Audio backend for now. */
|
/* No exclusive mode with the Core Audio backend for now. */
|
||||||
if (((pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) && pConfig->capture.shareMode == ma_share_mode_exclusive) ||
|
if (((pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) && pDescriptorCapture->shareMode == ma_share_mode_exclusive) ||
|
||||||
((pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) && pConfig->playback.shareMode == ma_share_mode_exclusive)) {
|
((pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) && pDescriptorPlayback->shareMode == ma_share_mode_exclusive)) {
|
||||||
return MA_SHARE_MODE_NOT_SUPPORTED;
|
return MA_SHARE_MODE_NOT_SUPPORTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -26579,18 +26587,15 @@ static ma_result ma_device_init__coreaudio(ma_context* pContext, const ma_device
|
|||||||
if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) {
|
if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) {
|
||||||
ma_device_init_internal_data__coreaudio data;
|
ma_device_init_internal_data__coreaudio data;
|
||||||
data.allowNominalSampleRateChange = pConfig->coreaudio.allowNominalSampleRateChange;
|
data.allowNominalSampleRateChange = pConfig->coreaudio.allowNominalSampleRateChange;
|
||||||
data.formatIn = pConfig->capture.format;
|
data.formatIn = pDescriptorCapture->format;
|
||||||
data.channelsIn = pConfig->capture.channels;
|
data.channelsIn = pDescriptorCapture->channels;
|
||||||
data.sampleRateIn = pConfig->sampleRate;
|
data.sampleRateIn = pDescriptorCapture->sampleRate;
|
||||||
MA_COPY_MEMORY(data.channelMapIn, pConfig->capture.channelMap, sizeof(pConfig->capture.channelMap));
|
MA_COPY_MEMORY(data.channelMapIn, pDescriptorCapture->channelMap, sizeof(pDescriptorCapture->channelMap));
|
||||||
data.usingDefaultFormat = pDevice->capture.usingDefaultFormat;
|
data.periodSizeInFramesIn = pDescriptorCapture->periodSizeInFrames;
|
||||||
data.usingDefaultChannels = pDevice->capture.usingDefaultChannels;
|
data.periodSizeInMillisecondsIn = pDescriptorCapture->periodSizeInMilliseconds;
|
||||||
data.usingDefaultSampleRate = pDevice->usingDefaultSampleRate;
|
data.periodsIn = pDescriptorCapture->periodCount;
|
||||||
data.usingDefaultChannelMap = pDevice->capture.usingDefaultChannelMap;
|
data.shareMode = pDescriptorCapture->shareMode;
|
||||||
data.shareMode = pConfig->capture.shareMode;
|
data.performanceProfile = pConfig->performanceProfile;
|
||||||
data.periodSizeInFramesIn = pConfig->periodSizeInFrames;
|
|
||||||
data.periodSizeInMillisecondsIn = pConfig->periodSizeInMilliseconds;
|
|
||||||
data.periodsIn = pConfig->periods;
|
|
||||||
data.registerStopEvent = MA_TRUE;
|
data.registerStopEvent = MA_TRUE;
|
||||||
|
|
||||||
/* Need at least 3 periods for duplex. */
|
/* Need at least 3 periods for duplex. */
|
||||||
@@ -26598,25 +26603,29 @@ static ma_result ma_device_init__coreaudio(ma_context* pContext, const ma_device
|
|||||||
data.periodsIn = 3;
|
data.periodsIn = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
result = ma_device_init_internal__coreaudio(pDevice->pContext, ma_device_type_capture, pConfig->capture.pDeviceID, &data, (void*)pDevice);
|
result = ma_device_init_internal__coreaudio(pDevice->pContext, ma_device_type_capture, pDescriptorCapture->pDeviceID, &data, (void*)pDevice);
|
||||||
if (result != MA_SUCCESS) {
|
if (result != MA_SUCCESS) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
pDevice->coreaudio.isDefaultCaptureDevice = (pConfig->capture.pDeviceID == NULL);
|
pDevice->coreaudio.isDefaultCaptureDevice = (pConfig->capture.pDeviceID == NULL);
|
||||||
#if defined(MA_APPLE_DESKTOP)
|
#if defined(MA_APPLE_DESKTOP)
|
||||||
pDevice->coreaudio.deviceObjectIDCapture = (ma_uint32)data.deviceObjectID;
|
pDevice->coreaudio.deviceObjectIDCapture = (ma_uint32)data.deviceObjectID;
|
||||||
#endif
|
#endif
|
||||||
pDevice->coreaudio.audioUnitCapture = (ma_ptr)data.audioUnit;
|
pDevice->coreaudio.audioUnitCapture = (ma_ptr)data.audioUnit;
|
||||||
pDevice->coreaudio.pAudioBufferList = (ma_ptr)data.pAudioBufferList;
|
pDevice->coreaudio.pAudioBufferList = (ma_ptr)data.pAudioBufferList;
|
||||||
pDevice->coreaudio.audioBufferCapInFrames = data.periodSizeInFramesOut;
|
pDevice->coreaudio.audioBufferCapInFrames = data.periodSizeInFramesOut;
|
||||||
|
pDevice->coreaudio.originalPeriodSizeInFrames = pDescriptorCapture->periodSizeInFrames;
|
||||||
|
pDevice->coreaudio.originalPeriodSizeInMilliseconds = pDescriptorCapture->periodSizeInMilliseconds;
|
||||||
|
pDevice->coreaudio.originalPeriods = pDescriptorCapture->periodCount;
|
||||||
|
pDevice->coreaudio.originalPerformanceProfile = pConfig->performanceProfile;
|
||||||
|
|
||||||
pDevice->capture.internalFormat = data.formatOut;
|
pDescriptorCapture->format = data.formatOut;
|
||||||
pDevice->capture.internalChannels = data.channelsOut;
|
pDescriptorCapture->channels = data.channelsOut;
|
||||||
pDevice->capture.internalSampleRate = data.sampleRateOut;
|
pDescriptorCapture->sampleRate = data.sampleRateOut;
|
||||||
MA_COPY_MEMORY(pDevice->capture.internalChannelMap, data.channelMapOut, sizeof(data.channelMapOut));
|
MA_COPY_MEMORY(pDescriptorCapture->channelMap, data.channelMapOut, sizeof(data.channelMapOut));
|
||||||
pDevice->capture.internalPeriodSizeInFrames = data.periodSizeInFramesOut;
|
pDescriptorCapture->periodSizeInFrames = data.periodSizeInFramesOut;
|
||||||
pDevice->capture.internalPeriods = data.periodsOut;
|
pDescriptorCapture->periodCount = data.periodsOut;
|
||||||
|
|
||||||
#if defined(MA_APPLE_DESKTOP)
|
#if defined(MA_APPLE_DESKTOP)
|
||||||
/*
|
/*
|
||||||
@@ -26632,30 +26641,27 @@ static ma_result ma_device_init__coreaudio(ma_context* pContext, const ma_device
|
|||||||
/* Playback. */
|
/* Playback. */
|
||||||
if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
|
if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
|
||||||
ma_device_init_internal_data__coreaudio data;
|
ma_device_init_internal_data__coreaudio data;
|
||||||
data.allowNominalSampleRateChange = pConfig->coreaudio.allowNominalSampleRateChange;
|
data.allowNominalSampleRateChange = pConfig->coreaudio.allowNominalSampleRateChange;
|
||||||
data.formatIn = pConfig->playback.format;
|
data.formatIn = pDescriptorPlayback->format;
|
||||||
data.channelsIn = pConfig->playback.channels;
|
data.channelsIn = pDescriptorPlayback->channels;
|
||||||
data.sampleRateIn = pConfig->sampleRate;
|
data.sampleRateIn = pDescriptorPlayback->sampleRate;
|
||||||
MA_COPY_MEMORY(data.channelMapIn, pConfig->playback.channelMap, sizeof(pConfig->playback.channelMap));
|
MA_COPY_MEMORY(data.channelMapIn, pDescriptorPlayback->channelMap, sizeof(pDescriptorPlayback->channelMap));
|
||||||
data.usingDefaultFormat = pDevice->playback.usingDefaultFormat;
|
data.shareMode = pDescriptorPlayback->shareMode;
|
||||||
data.usingDefaultChannels = pDevice->playback.usingDefaultChannels;
|
data.shareMode = pDescriptorPlayback->shareMode;
|
||||||
data.usingDefaultSampleRate = pDevice->usingDefaultSampleRate;
|
|
||||||
data.usingDefaultChannelMap = pDevice->playback.usingDefaultChannelMap;
|
|
||||||
data.shareMode = pConfig->playback.shareMode;
|
|
||||||
|
|
||||||
/* In full-duplex mode we want the playback buffer to be the same size as the capture buffer. */
|
/* In full-duplex mode we want the playback buffer to be the same size as the capture buffer. */
|
||||||
if (pConfig->deviceType == ma_device_type_duplex) {
|
if (pConfig->deviceType == ma_device_type_duplex) {
|
||||||
data.periodSizeInFramesIn = pDevice->capture.internalPeriodSizeInFrames;
|
data.periodSizeInFramesIn = pDescriptorCapture->periodSizeInFrames;
|
||||||
data.periodsIn = pDevice->capture.internalPeriods;
|
data.periodsIn = pDescriptorCapture->periodCount;
|
||||||
data.registerStopEvent = MA_FALSE;
|
data.registerStopEvent = MA_FALSE;
|
||||||
} else {
|
} else {
|
||||||
data.periodSizeInFramesIn = pConfig->periodSizeInFrames;
|
data.periodSizeInFramesIn = pDescriptorPlayback->periodSizeInFrames;
|
||||||
data.periodSizeInMillisecondsIn = pConfig->periodSizeInMilliseconds;
|
data.periodSizeInMillisecondsIn = pDescriptorPlayback->periodSizeInMilliseconds;
|
||||||
data.periodsIn = pConfig->periods;
|
data.periodsIn = pDescriptorPlayback->periodCount;
|
||||||
data.registerStopEvent = MA_TRUE;
|
data.registerStopEvent = MA_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
result = ma_device_init_internal__coreaudio(pDevice->pContext, ma_device_type_playback, pConfig->playback.pDeviceID, &data, (void*)pDevice);
|
result = ma_device_init_internal__coreaudio(pDevice->pContext, ma_device_type_playback, pDescriptorPlayback->pDeviceID, &data, (void*)pDevice);
|
||||||
if (result != MA_SUCCESS) {
|
if (result != MA_SUCCESS) {
|
||||||
if (pConfig->deviceType == ma_device_type_duplex) {
|
if (pConfig->deviceType == ma_device_type_duplex) {
|
||||||
((ma_AudioComponentInstanceDispose_proc)pDevice->pContext->coreaudio.AudioComponentInstanceDispose)((AudioUnit)pDevice->coreaudio.audioUnitCapture);
|
((ma_AudioComponentInstanceDispose_proc)pDevice->pContext->coreaudio.AudioComponentInstanceDispose)((AudioUnit)pDevice->coreaudio.audioUnitCapture);
|
||||||
@@ -26666,33 +26672,35 @@ static ma_result ma_device_init__coreaudio(ma_context* pContext, const ma_device
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
pDevice->coreaudio.isDefaultPlaybackDevice = (pConfig->playback.pDeviceID == NULL);
|
pDevice->coreaudio.isDefaultPlaybackDevice = (pConfig->playback.pDeviceID == NULL);
|
||||||
#if defined(MA_APPLE_DESKTOP)
|
#if defined(MA_APPLE_DESKTOP)
|
||||||
pDevice->coreaudio.deviceObjectIDPlayback = (ma_uint32)data.deviceObjectID;
|
pDevice->coreaudio.deviceObjectIDPlayback = (ma_uint32)data.deviceObjectID;
|
||||||
#endif
|
#endif
|
||||||
pDevice->coreaudio.audioUnitPlayback = (ma_ptr)data.audioUnit;
|
pDevice->coreaudio.audioUnitPlayback = (ma_ptr)data.audioUnit;
|
||||||
|
pDevice->coreaudio.originalPeriodSizeInFrames = pDescriptorPlayback->periodSizeInFrames;
|
||||||
|
pDevice->coreaudio.originalPeriodSizeInMilliseconds = pDescriptorPlayback->periodSizeInMilliseconds;
|
||||||
|
pDevice->coreaudio.originalPeriods = pDescriptorPlayback->periodCount;
|
||||||
|
pDevice->coreaudio.originalPerformanceProfile = pConfig->performanceProfile;
|
||||||
|
|
||||||
pDevice->playback.internalFormat = data.formatOut;
|
pDescriptorPlayback->format = data.formatOut;
|
||||||
pDevice->playback.internalChannels = data.channelsOut;
|
pDescriptorPlayback->channels = data.channelsOut;
|
||||||
pDevice->playback.internalSampleRate = data.sampleRateOut;
|
pDescriptorPlayback->sampleRate = data.sampleRateOut;
|
||||||
MA_COPY_MEMORY(pDevice->playback.internalChannelMap, data.channelMapOut, sizeof(data.channelMapOut));
|
MA_COPY_MEMORY(pDescriptorPlayback->channelMap, data.channelMapOut, sizeof(data.channelMapOut));
|
||||||
pDevice->playback.internalPeriodSizeInFrames = data.periodSizeInFramesOut;
|
pDescriptorPlayback->periodSizeInFrames = data.periodSizeInFramesOut;
|
||||||
pDevice->playback.internalPeriods = data.periodsOut;
|
pDescriptorPlayback->periodCount = data.periodsOut;
|
||||||
|
|
||||||
#if defined(MA_APPLE_DESKTOP)
|
#if defined(MA_APPLE_DESKTOP)
|
||||||
/*
|
/*
|
||||||
If we are using the default device we'll need to listen for changes to the system's default device so we can seemlessly
|
If we are using the default device we'll need to listen for changes to the system's default device so we can seemlessly
|
||||||
switch the device in the background.
|
switch the device in the background.
|
||||||
*/
|
*/
|
||||||
if (pConfig->playback.pDeviceID == NULL && (pConfig->deviceType != ma_device_type_duplex || pConfig->capture.pDeviceID != NULL)) {
|
if (pDescriptorPlayback->pDeviceID == NULL && (pConfig->deviceType != ma_device_type_duplex || pDescriptorCapture->pDeviceID != NULL)) {
|
||||||
ma_device__track__coreaudio(pDevice);
|
ma_device__track__coreaudio(pDevice);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
pDevice->coreaudio.originalPeriodSizeInFrames = pConfig->periodSizeInFrames;
|
|
||||||
pDevice->coreaudio.originalPeriodSizeInMilliseconds = pConfig->periodSizeInMilliseconds;
|
|
||||||
pDevice->coreaudio.originalPeriods = pConfig->periods;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
When stopping the device, a callback is called on another thread. We need to wait for this callback
|
When stopping the device, a callback is called on another thread. We need to wait for this callback
|
||||||
@@ -26700,26 +26708,6 @@ static ma_result ma_device_init__coreaudio(ma_context* pContext, const ma_device
|
|||||||
*/
|
*/
|
||||||
ma_event_init(&pDevice->coreaudio.stopEvent);
|
ma_event_init(&pDevice->coreaudio.stopEvent);
|
||||||
|
|
||||||
/* Need a ring buffer for duplex mode. */
|
|
||||||
if (pConfig->deviceType == ma_device_type_duplex) {
|
|
||||||
ma_uint32 rbSizeInFrames = (ma_uint32)ma_calculate_frame_count_after_resampling(pDevice->sampleRate, pDevice->capture.internalSampleRate, pDevice->capture.internalPeriodSizeInFrames * pDevice->capture.internalPeriods);
|
|
||||||
ma_result result = ma_pcm_rb_init(pDevice->capture.format, pDevice->capture.channels, rbSizeInFrames, NULL, &pDevice->pContext->allocationCallbacks, &pDevice->coreaudio.duplexRB);
|
|
||||||
if (result != MA_SUCCESS) {
|
|
||||||
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[Core Audio] Failed to initialize ring buffer.", result);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We need a period to act as a buffer for cases where the playback and capture device's end up desyncing. */
|
|
||||||
{
|
|
||||||
ma_uint32 bufferSizeInFrames = rbSizeInFrames / pDevice->capture.internalPeriods;
|
|
||||||
void* pBufferData;
|
|
||||||
ma_pcm_rb_acquire_write(&pDevice->coreaudio.duplexRB, &bufferSizeInFrames, &pBufferData);
|
|
||||||
{
|
|
||||||
MA_ZERO_MEMORY(pBufferData, bufferSizeInFrames * ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels));
|
|
||||||
}
|
|
||||||
ma_pcm_rb_commit_write(&pDevice->coreaudio.duplexRB, bufferSizeInFrames, pBufferData);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
We need to detect when a route has changed so we can update the data conversion pipeline accordingly. This is done
|
We need to detect when a route has changed so we can update the data conversion pipeline accordingly. This is done
|
||||||
differently on non-Desktop Apple platforms.
|
differently on non-Desktop Apple platforms.
|
||||||
@@ -26830,7 +26818,7 @@ static AVAudioSessionCategory ma_to_AVAudioSessionCategory(ma_ios_session_catego
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static ma_result ma_context_init__coreaudio(const ma_context_config* pConfig, ma_context* pContext)
|
static ma_result ma_context_init__coreaudio(ma_context* pContext, const ma_context_config* pConfig, ma_backend_callbacks* pCallbacks)
|
||||||
{
|
{
|
||||||
#if !defined(MA_APPLE_MOBILE)
|
#if !defined(MA_APPLE_MOBILE)
|
||||||
ma_result result;
|
ma_result result;
|
||||||
@@ -27000,15 +26988,17 @@ static ma_result ma_context_init__coreaudio(const ma_context_config* pConfig, ma
|
|||||||
|
|
||||||
pContext->coreaudio.noAudioSessionDeactivate = pConfig->coreaudio.noAudioSessionDeactivate;
|
pContext->coreaudio.noAudioSessionDeactivate = pConfig->coreaudio.noAudioSessionDeactivate;
|
||||||
|
|
||||||
pContext->isBackendAsynchronous = MA_TRUE;
|
pCallbacks->onContextInit = ma_context_init__coreaudio;
|
||||||
|
pCallbacks->onContextUninit = ma_context_uninit__coreaudio;
|
||||||
pContext->onUninit = ma_context_uninit__coreaudio;
|
pCallbacks->onContextEnumerateDevices = ma_context_enumerate_devices__coreaudio;
|
||||||
pContext->onEnumDevices = ma_context_enumerate_devices__coreaudio;
|
pCallbacks->onContextGetDeviceInfo = ma_context_get_device_info__coreaudio;
|
||||||
pContext->onGetDeviceInfo = ma_context_get_device_info__coreaudio;
|
pCallbacks->onDeviceInit = ma_device_init__coreaudio;
|
||||||
pContext->onDeviceInit = ma_device_init__coreaudio;
|
pCallbacks->onDeviceUninit = ma_device_uninit__coreaudio;
|
||||||
pContext->onDeviceUninit = ma_device_uninit__coreaudio;
|
pCallbacks->onDeviceStart = ma_device_start__coreaudio;
|
||||||
pContext->onDeviceStart = ma_device_start__coreaudio;
|
pCallbacks->onDeviceStop = ma_device_stop__coreaudio;
|
||||||
pContext->onDeviceStop = ma_device_stop__coreaudio;
|
pCallbacks->onDeviceRead = NULL;
|
||||||
|
pCallbacks->onDeviceWrite = NULL;
|
||||||
|
pCallbacks->onDeviceAudioThread = NULL;
|
||||||
|
|
||||||
return MA_SUCCESS;
|
return MA_SUCCESS;
|
||||||
}
|
}
|
||||||
@@ -32815,6 +32805,12 @@ MA_API ma_result ma_context_init(const ma_backend backends[], ma_uint32 backendC
|
|||||||
pContext->callbacks.onContextInit = ma_context_init__winmm;
|
pContext->callbacks.onContextInit = ma_context_init__winmm;
|
||||||
} break;
|
} break;
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef MA_HAS_COREAUDIO
|
||||||
|
case ma_backend_coreaudio:
|
||||||
|
{
|
||||||
|
pContext->callbacks.onContextInit = ma_context_init__coreaudio;
|
||||||
|
} break;
|
||||||
|
#endif
|
||||||
#ifdef MA_HAS_PULSEAUDIO
|
#ifdef MA_HAS_PULSEAUDIO
|
||||||
case ma_backend_pulseaudio:
|
case ma_backend_pulseaudio:
|
||||||
{
|
{
|
||||||
@@ -32898,8 +32894,7 @@ MA_API ma_result ma_context_init(const ma_backend backends[], ma_uint32 backendC
|
|||||||
#ifdef MA_HAS_COREAUDIO
|
#ifdef MA_HAS_COREAUDIO
|
||||||
case ma_backend_coreaudio:
|
case ma_backend_coreaudio:
|
||||||
{
|
{
|
||||||
ma_post_log_message(pContext, NULL, MA_LOG_LEVEL_VERBOSE, "Attempting to initialize CoreAudio backend...");
|
/*result = ma_context_init__coreaudio(pConfig, pContext);*/
|
||||||
result = ma_context_init__coreaudio(pConfig, pContext);
|
|
||||||
} break;
|
} break;
|
||||||
#endif
|
#endif
|
||||||
#ifdef MA_HAS_SNDIO
|
#ifdef MA_HAS_SNDIO
|
||||||
@@ -33665,7 +33660,7 @@ MA_API ma_result ma_device_init(ma_context* pContext, const ma_device_config* pC
|
|||||||
if (ma_context__is_using_new_callbacks(pContext)) { /* <-- TEMP: Will be removed once all asynchronous backends have been converted to the new callbacks. */
|
if (ma_context__is_using_new_callbacks(pContext)) { /* <-- TEMP: Will be removed once all asynchronous backends have been converted to the new callbacks. */
|
||||||
if (ma_context_is_backend_asynchronous(pContext)) {
|
if (ma_context_is_backend_asynchronous(pContext)) {
|
||||||
if (pConfig->deviceType == ma_device_type_duplex) {
|
if (pConfig->deviceType == ma_device_type_duplex) {
|
||||||
result = ma_duplex_rb_init(pDevice->sampleRate, pDevice->capture.internalFormat, pDevice->capture.internalChannels, pDevice->capture.internalSampleRate, pDevice->capture.internalPeriodSizeInFrames, &pDevice->pContext->allocationCallbacks, &pDevice->duplexRB);
|
result = ma_duplex_rb_init(pDevice->capture.format, pDevice->capture.channels, pDevice->sampleRate, pDevice->capture.internalSampleRate, pDevice->capture.internalPeriodSizeInFrames, &pDevice->pContext->allocationCallbacks, &pDevice->duplexRB);
|
||||||
if (result != MA_SUCCESS) {
|
if (result != MA_SUCCESS) {
|
||||||
ma_device_uninit(pDevice);
|
ma_device_uninit(pDevice);
|
||||||
return result;
|
return result;
|
||||||
@@ -43152,12 +43147,12 @@ MA_API void* ma_pcm_rb_get_subbuffer_ptr(ma_pcm_rb* pRB, ma_uint32 subbufferInde
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
MA_API ma_result ma_duplex_rb_init(ma_uint32 inputSampleRate, ma_format captureFormat, ma_uint32 captureChannels, ma_uint32 captureSampleRate, ma_uint32 capturePeriodSizeInFrames, const ma_allocation_callbacks* pAllocationCallbacks, ma_duplex_rb* pRB)
|
MA_API ma_result ma_duplex_rb_init(ma_format captureFormat, ma_uint32 captureChannels, ma_uint32 sampleRate, ma_uint32 captureInternalSampleRate, ma_uint32 captureInternalPeriodSizeInFrames, const ma_allocation_callbacks* pAllocationCallbacks, ma_duplex_rb* pRB)
|
||||||
{
|
{
|
||||||
ma_result result;
|
ma_result result;
|
||||||
ma_uint32 sizeInFrames;
|
ma_uint32 sizeInFrames;
|
||||||
|
|
||||||
sizeInFrames = (ma_uint32)ma_calculate_frame_count_after_resampling(inputSampleRate, captureSampleRate, capturePeriodSizeInFrames * 5);
|
sizeInFrames = (ma_uint32)ma_calculate_frame_count_after_resampling(sampleRate, captureInternalSampleRate, captureInternalPeriodSizeInFrames * 5);
|
||||||
if (sizeInFrames == 0) {
|
if (sizeInFrames == 0) {
|
||||||
return MA_INVALID_ARGS;
|
return MA_INVALID_ARGS;
|
||||||
}
|
}
|
||||||
@@ -43168,7 +43163,7 @@ MA_API ma_result ma_duplex_rb_init(ma_uint32 inputSampleRate, ma_format captureF
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Seek forward a bit so we have a bit of a buffer in case of desyncs. */
|
/* Seek forward a bit so we have a bit of a buffer in case of desyncs. */
|
||||||
ma_pcm_rb_seek_write((ma_pcm_rb*)pRB, capturePeriodSizeInFrames * 2);
|
ma_pcm_rb_seek_write((ma_pcm_rb*)pRB, captureInternalPeriodSizeInFrames * 2);
|
||||||
|
|
||||||
return MA_SUCCESS;
|
return MA_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user