// The stop event is a bit annoying in Core Audio because it will be called when we automatically switch the default device. Some scenarios to consider:
//
// 1) When the device is unplugged, this will be called _before_ the default device change notification.
// 2) When the device is changed via the default device change notification, this will be called _after_ the switch.
//
// For case #1, we just check if there's a new default device available. If so, we just ignore the stop event. For case #2 we check a flag.
if (pDevice->isDefaultDevice && mal_device__get_state(pDevice) != MAL_STATE_STOPPING) {
// It looks like the device is switching through an external event, such as the user unplugging the device or changing the default device
// via the operating system's sound settings. If we're re-initializing the device, we just terminate because we want the stopping of the
// device to be seamless to the client (we don't want them receiving the onStop event and thinking that the device has stopped when it
// hasn't!).
if (pDevice->coreaudio.isSwitchingDevice) {
return;
}
// Getting here means the device is not reinitializing which means it may have been unplugged. From what I can see, it looks like Core Audio
// will try switching to the new default device seamlessly. We need to somehow find a way to determine whether or not Core Audio will most
// likely be successful in switching to the new device.
//
// TODO: Try to predict if Core Audio will switch devices. If not, the onStop callback needs to be posted.
AudioBufferList* pAudioBufferList; // Only used for input devices.
mal_format formatOut;
mal_uint32 channelsOut;
mal_uint32 sampleRateOut;
mal_channel channelMapOut[MAL_MAX_CHANNELS];
mal_uint32 bufferSizeInFramesOut;
mal_uint32 periodsOut;
mal_bool32 exclusiveMode;
char deviceName[256];
} mal_device_init_internal_data__coreaudio;
mal_result mal_device_init_internal__coreaudio(mal_context* pContext, mal_device_type deviceType, const mal_device_id* pDeviceID, mal_device_init_internal_data__coreaudio* pData, void* pDevice_DoNotReference) /* <-- pDevice is typed as void* intentionally so as to avoid accidentally referencing it. */
OSStatus status = ((mal_AudioComponentInstanceNew_proc)pContext->coreaudio.AudioComponentInstanceNew)((AudioComponent)pDevice->coreaudio.component, (AudioUnit*)&pDevice->coreaudio.audioUnit);
OSStatus status = ((mal_AudioComponentInstanceNew_proc)pContext->coreaudio.AudioComponentInstanceNew)(pData->component, (AudioUnit*)&pData->audioUnit);
if (status != noErr) {
if (status != noErr) {
return mal_result_from_OSStatus(status);
return mal_result_from_OSStatus(status);
}
}
...
@@ -14833,25 +14933,25 @@ mal_result mal_device_init__coreaudio(mal_context* pContext, mal_device_type dev
...
@@ -14833,25 +14933,25 @@ mal_result mal_device_init__coreaudio(mal_context* pContext, mal_device_type dev
enableIOFlag = 0;
enableIOFlag = 0;
}
}
status = ((mal_AudioUnitSetProperty_proc)pContext->coreaudio.AudioUnitSetProperty)((AudioUnit)pDevice->coreaudio.audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, MAL_COREAUDIO_OUTPUT_BUS, &enableIOFlag, sizeof(enableIOFlag));
status = ((mal_AudioUnitSetProperty_proc)pContext->coreaudio.AudioUnitSetProperty)(pData->audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, MAL_COREAUDIO_OUTPUT_BUS, &enableIOFlag, sizeof(enableIOFlag));