mirror of
https://github.com/libsdl-org/SDL.git
synced 2025-09-05 19:08:12 +00:00
coreaudio: Change _this
to device
This commit is contained in:
@@ -323,18 +323,18 @@ static void resume_audio_devices(void)
|
||||
}
|
||||
}
|
||||
|
||||
static void interruption_begin(SDL_AudioDevice *_this)
|
||||
static void interruption_begin(SDL_AudioDevice *device)
|
||||
{
|
||||
if (_this != NULL && _this->hidden->audioQueue != NULL) {
|
||||
_this->hidden->interrupted = SDL_TRUE;
|
||||
AudioQueuePause(_this->hidden->audioQueue);
|
||||
if (device != NULL && device->hidden->audioQueue != NULL) {
|
||||
device->hidden->interrupted = SDL_TRUE;
|
||||
AudioQueuePause(device->hidden->audioQueue);
|
||||
}
|
||||
}
|
||||
|
||||
static void interruption_end(SDL_AudioDevice *_this)
|
||||
static void interruption_end(SDL_AudioDevice *device)
|
||||
{
|
||||
if (_this != NULL && _this->hidden != NULL && _this->hidden->audioQueue != NULL && _this->hidden->interrupted && AudioQueueStart(_this->hidden->audioQueue, NULL) == AVAudioSessionErrorCodeNone) {
|
||||
_this->hidden->interrupted = SDL_FALSE;
|
||||
if (device != NULL && device->hidden != NULL && device->hidden->audioQueue != NULL && device->hidden->interrupted && AudioQueueStart(device->hidden->audioQueue, NULL) == AVAudioSessionErrorCodeNone) {
|
||||
device->hidden->interrupted = SDL_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -367,7 +367,7 @@ static void interruption_end(SDL_AudioDevice *_this)
|
||||
|
||||
@end
|
||||
|
||||
static BOOL update_audio_session(SDL_AudioDevice *_this, SDL_bool open, SDL_bool allow_playandrecord)
|
||||
static BOOL update_audio_session(SDL_AudioDevice *device, SDL_bool open, SDL_bool allow_playandrecord)
|
||||
{
|
||||
@autoreleasepool {
|
||||
AVAudioSession *session = [AVAudioSession sharedInstance];
|
||||
@@ -455,7 +455,7 @@ static BOOL update_audio_session(SDL_AudioDevice *_this, SDL_bool open, SDL_bool
|
||||
if (![session setActive:YES error:&err]) {
|
||||
if ([err code] == AVAudioSessionErrorCodeResourceNotAvailable &&
|
||||
category == AVAudioSessionCategoryPlayAndRecord) {
|
||||
return update_audio_session(_this, open, SDL_FALSE);
|
||||
return update_audio_session(device, open, SDL_FALSE);
|
||||
}
|
||||
|
||||
NSString *desc = err.description;
|
||||
@@ -472,7 +472,7 @@ static BOOL update_audio_session(SDL_AudioDevice *_this, SDL_bool open, SDL_bool
|
||||
|
||||
if (open) {
|
||||
SDLInterruptionListener *listener = [SDLInterruptionListener new];
|
||||
listener.device = _this;
|
||||
listener.device = device;
|
||||
|
||||
[center addObserver:listener
|
||||
selector:@selector(audioSessionInterruption:)
|
||||
@@ -493,10 +493,10 @@ static BOOL update_audio_session(SDL_AudioDevice *_this, SDL_bool open, SDL_bool
|
||||
name:UIApplicationWillEnterForegroundNotification
|
||||
object:nil];
|
||||
|
||||
_this->hidden->interruption_listener = CFBridgingRetain(listener);
|
||||
device->hidden->interruption_listener = CFBridgingRetain(listener);
|
||||
} else {
|
||||
SDLInterruptionListener *listener = nil;
|
||||
listener = (SDLInterruptionListener *)CFBridgingRelease(_this->hidden->interruption_listener);
|
||||
listener = (SDLInterruptionListener *)CFBridgingRelease(device->hidden->interruption_listener);
|
||||
[center removeObserver:listener];
|
||||
@synchronized(listener) {
|
||||
listener.device = NULL;
|
||||
@@ -511,47 +511,47 @@ static BOOL update_audio_session(SDL_AudioDevice *_this, SDL_bool open, SDL_bool
|
||||
/* The AudioQueue callback */
|
||||
static void outputCallback(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer)
|
||||
{
|
||||
SDL_AudioDevice *_this = (SDL_AudioDevice *)inUserData;
|
||||
SDL_AudioDevice *device = (SDL_AudioDevice *)inUserData;
|
||||
|
||||
/* This flag is set before _this->mixer_lock is destroyed during
|
||||
/* This flag is set before device->mixer_lock is destroyed during
|
||||
shutdown, so check it before grabbing the mutex, and then check it
|
||||
again _after_ in case we blocked waiting on the lock. */
|
||||
if (SDL_AtomicGet(&_this->shutdown)) {
|
||||
if (SDL_AtomicGet(&device->shutdown)) {
|
||||
return; /* don't do anything, since we don't even want to enqueue this buffer again. */
|
||||
}
|
||||
|
||||
SDL_LockMutex(_this->mixer_lock);
|
||||
SDL_LockMutex(device->mixer_lock);
|
||||
|
||||
if (SDL_AtomicGet(&_this->shutdown)) {
|
||||
SDL_UnlockMutex(_this->mixer_lock);
|
||||
if (SDL_AtomicGet(&device->shutdown)) {
|
||||
SDL_UnlockMutex(device->mixer_lock);
|
||||
return; /* don't do anything, since we don't even want to enqueue this buffer again. */
|
||||
}
|
||||
|
||||
if (!SDL_AtomicGet(&_this->enabled) || SDL_AtomicGet(&_this->paused)) {
|
||||
if (!SDL_AtomicGet(&device->enabled) || SDL_AtomicGet(&device->paused)) {
|
||||
/* Supply silence if audio is not enabled or paused */
|
||||
SDL_memset(inBuffer->mAudioData, _this->spec.silence, inBuffer->mAudioDataBytesCapacity);
|
||||
} else if (_this->stream) {
|
||||
SDL_memset(inBuffer->mAudioData, device->spec.silence, inBuffer->mAudioDataBytesCapacity);
|
||||
} else if (device->stream) {
|
||||
UInt32 remaining = inBuffer->mAudioDataBytesCapacity;
|
||||
Uint8 *ptr = (Uint8 *)inBuffer->mAudioData;
|
||||
|
||||
while (remaining > 0) {
|
||||
if (SDL_GetAudioStreamAvailable(_this->stream) == 0) {
|
||||
if (SDL_GetAudioStreamAvailable(device->stream) == 0) {
|
||||
/* Generate the data */
|
||||
(*_this->callbackspec.callback)(_this->callbackspec.userdata,
|
||||
_this->hidden->buffer, _this->hidden->bufferSize);
|
||||
_this->hidden->bufferOffset = 0;
|
||||
SDL_PutAudioStreamData(_this->stream, _this->hidden->buffer, _this->hidden->bufferSize);
|
||||
(*device->callbackspec.callback)(device->callbackspec.userdata,
|
||||
device->hidden->buffer, device->hidden->bufferSize);
|
||||
device->hidden->bufferOffset = 0;
|
||||
SDL_PutAudioStreamData(device->stream, device->hidden->buffer, device->hidden->bufferSize);
|
||||
}
|
||||
if (SDL_GetAudioStreamAvailable(_this->stream) > 0) {
|
||||
if (SDL_GetAudioStreamAvailable(device->stream) > 0) {
|
||||
int got;
|
||||
UInt32 len = SDL_GetAudioStreamAvailable(_this->stream);
|
||||
UInt32 len = SDL_GetAudioStreamAvailable(device->stream);
|
||||
if (len > remaining) {
|
||||
len = remaining;
|
||||
}
|
||||
got = SDL_GetAudioStreamData(_this->stream, ptr, len);
|
||||
got = SDL_GetAudioStreamData(device->stream, ptr, len);
|
||||
SDL_assert((got < 0) || (got == len));
|
||||
if (got != len) {
|
||||
SDL_memset(ptr, _this->spec.silence, len);
|
||||
SDL_memset(ptr, device->spec.silence, len);
|
||||
}
|
||||
ptr = ptr + len;
|
||||
remaining -= len;
|
||||
@@ -563,66 +563,66 @@ static void outputCallback(void *inUserData, AudioQueueRef inAQ, AudioQueueBuffe
|
||||
|
||||
while (remaining > 0) {
|
||||
UInt32 len;
|
||||
if (_this->hidden->bufferOffset >= _this->hidden->bufferSize) {
|
||||
if (device->hidden->bufferOffset >= device->hidden->bufferSize) {
|
||||
/* Generate the data */
|
||||
(*_this->callbackspec.callback)(_this->callbackspec.userdata,
|
||||
_this->hidden->buffer, _this->hidden->bufferSize);
|
||||
_this->hidden->bufferOffset = 0;
|
||||
(*device->callbackspec.callback)(device->callbackspec.userdata,
|
||||
device->hidden->buffer, device->hidden->bufferSize);
|
||||
device->hidden->bufferOffset = 0;
|
||||
}
|
||||
|
||||
len = _this->hidden->bufferSize - _this->hidden->bufferOffset;
|
||||
len = device->hidden->bufferSize - device->hidden->bufferOffset;
|
||||
if (len > remaining) {
|
||||
len = remaining;
|
||||
}
|
||||
SDL_memcpy(ptr, (char *)_this->hidden->buffer + _this->hidden->bufferOffset, len);
|
||||
SDL_memcpy(ptr, (char *)device->hidden->buffer + device->hidden->bufferOffset, len);
|
||||
ptr = ptr + len;
|
||||
remaining -= len;
|
||||
_this->hidden->bufferOffset += len;
|
||||
device->hidden->bufferOffset += len;
|
||||
}
|
||||
}
|
||||
|
||||
AudioQueueEnqueueBuffer(_this->hidden->audioQueue, inBuffer, 0, NULL);
|
||||
AudioQueueEnqueueBuffer(device->hidden->audioQueue, inBuffer, 0, NULL);
|
||||
|
||||
inBuffer->mAudioDataByteSize = inBuffer->mAudioDataBytesCapacity;
|
||||
|
||||
SDL_UnlockMutex(_this->mixer_lock);
|
||||
SDL_UnlockMutex(device->mixer_lock);
|
||||
}
|
||||
|
||||
static void inputCallback(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer,
|
||||
const AudioTimeStamp *inStartTime, UInt32 inNumberPacketDescriptions,
|
||||
const AudioStreamPacketDescription *inPacketDescs)
|
||||
{
|
||||
SDL_AudioDevice *_this = (SDL_AudioDevice *)inUserData;
|
||||
SDL_AudioDevice *device = (SDL_AudioDevice *)inUserData;
|
||||
|
||||
if (SDL_AtomicGet(&_this->shutdown)) {
|
||||
if (SDL_AtomicGet(&device->shutdown)) {
|
||||
return; /* don't do anything. */
|
||||
}
|
||||
|
||||
/* ignore unless we're active. */
|
||||
if (!SDL_AtomicGet(&_this->paused) && SDL_AtomicGet(&_this->enabled)) {
|
||||
if (!SDL_AtomicGet(&device->paused) && SDL_AtomicGet(&device->enabled)) {
|
||||
const Uint8 *ptr = (const Uint8 *)inBuffer->mAudioData;
|
||||
UInt32 remaining = inBuffer->mAudioDataByteSize;
|
||||
while (remaining > 0) {
|
||||
UInt32 len = _this->hidden->bufferSize - _this->hidden->bufferOffset;
|
||||
UInt32 len = device->hidden->bufferSize - device->hidden->bufferOffset;
|
||||
if (len > remaining) {
|
||||
len = remaining;
|
||||
}
|
||||
|
||||
SDL_memcpy((char *)_this->hidden->buffer + _this->hidden->bufferOffset, ptr, len);
|
||||
SDL_memcpy((char *)device->hidden->buffer + device->hidden->bufferOffset, ptr, len);
|
||||
ptr += len;
|
||||
remaining -= len;
|
||||
_this->hidden->bufferOffset += len;
|
||||
device->hidden->bufferOffset += len;
|
||||
|
||||
if (_this->hidden->bufferOffset >= _this->hidden->bufferSize) {
|
||||
SDL_LockMutex(_this->mixer_lock);
|
||||
(*_this->callbackspec.callback)(_this->callbackspec.userdata, _this->hidden->buffer, _this->hidden->bufferSize);
|
||||
SDL_UnlockMutex(_this->mixer_lock);
|
||||
_this->hidden->bufferOffset = 0;
|
||||
if (device->hidden->bufferOffset >= device->hidden->bufferSize) {
|
||||
SDL_LockMutex(device->mixer_lock);
|
||||
(*device->callbackspec.callback)(device->callbackspec.userdata, device->hidden->buffer, device->hidden->bufferSize);
|
||||
SDL_UnlockMutex(device->mixer_lock);
|
||||
device->hidden->bufferOffset = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AudioQueueEnqueueBuffer(_this->hidden->audioQueue, inBuffer, 0, NULL);
|
||||
AudioQueueEnqueueBuffer(device->hidden->audioQueue, inBuffer, 0, NULL);
|
||||
}
|
||||
|
||||
#ifdef MACOSX_COREAUDIO
|
||||
@@ -634,17 +634,17 @@ static const AudioObjectPropertyAddress alive_address = {
|
||||
|
||||
static OSStatus device_unplugged(AudioObjectID devid, UInt32 num_addr, const AudioObjectPropertyAddress *addrs, void *data)
|
||||
{
|
||||
SDL_AudioDevice *_this = (SDL_AudioDevice *)data;
|
||||
SDL_AudioDevice *device = (SDL_AudioDevice *)data;
|
||||
SDL_bool dead = SDL_FALSE;
|
||||
UInt32 isAlive = 1;
|
||||
UInt32 size = sizeof(isAlive);
|
||||
OSStatus error;
|
||||
|
||||
if (!SDL_AtomicGet(&_this->enabled)) {
|
||||
if (!SDL_AtomicGet(&device->enabled)) {
|
||||
return 0; /* already known to be dead. */
|
||||
}
|
||||
|
||||
error = AudioObjectGetPropertyData(_this->hidden->deviceID, &alive_address,
|
||||
error = AudioObjectGetPropertyData(device->hidden->deviceID, &alive_address,
|
||||
0, NULL, &size, &isAlive);
|
||||
|
||||
if (error == kAudioHardwareBadDeviceError) {
|
||||
@@ -654,7 +654,7 @@ static OSStatus device_unplugged(AudioObjectID devid, UInt32 num_addr, const Aud
|
||||
}
|
||||
|
||||
if (dead) {
|
||||
SDL_OpenedAudioDeviceDisconnected(_this);
|
||||
SDL_OpenedAudioDeviceDisconnected(device);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -663,41 +663,41 @@ static OSStatus device_unplugged(AudioObjectID devid, UInt32 num_addr, const Aud
|
||||
/* macOS calls this when the default device changed (if we have a default device open). */
|
||||
static OSStatus default_device_changed(AudioObjectID inObjectID, UInt32 inNumberAddresses, const AudioObjectPropertyAddress *inAddresses, void *inUserData)
|
||||
{
|
||||
SDL_AudioDevice *_this = (SDL_AudioDevice *)inUserData;
|
||||
SDL_AudioDevice *device = (SDL_AudioDevice *)inUserData;
|
||||
#if DEBUG_COREAUDIO
|
||||
printf("COREAUDIO: default device changed for SDL audio device %p!\n", _this);
|
||||
printf("COREAUDIO: default device changed for SDL audio device %p!\n", device);
|
||||
#endif
|
||||
SDL_AtomicSet(&_this->hidden->device_change_flag, 1); /* let the audioqueue thread pick up on this when safe to do so. */
|
||||
SDL_AtomicSet(&device->hidden->device_change_flag, 1); /* let the audioqueue thread pick up on this when safe to do so. */
|
||||
return noErr;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void COREAUDIO_CloseDevice(SDL_AudioDevice *_this)
|
||||
static void COREAUDIO_CloseDevice(SDL_AudioDevice *device)
|
||||
{
|
||||
const SDL_bool iscapture = _this->iscapture;
|
||||
const SDL_bool iscapture = device->iscapture;
|
||||
int i;
|
||||
|
||||
/* !!! FIXME: what does iOS do when a bluetooth audio device vanishes? Headphones unplugged? */
|
||||
/* !!! FIXME: (we only do a "default" device on iOS right now...can we do more?) */
|
||||
#ifdef MACOSX_COREAUDIO
|
||||
if (_this->handle != NULL) { /* we don't register this listener for default devices. */
|
||||
AudioObjectRemovePropertyListener(_this->hidden->deviceID, &alive_address, device_unplugged, _this);
|
||||
if (device->handle != NULL) { /* we don't register this listener for default devices. */
|
||||
AudioObjectRemovePropertyListener(device->hidden->deviceID, &alive_address, device_unplugged, device);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* if callback fires again, feed silence; don't call into the app. */
|
||||
SDL_AtomicSet(&_this->paused, 1);
|
||||
SDL_AtomicSet(&device->paused, 1);
|
||||
|
||||
/* dispose of the audio queue before waiting on the thread, or it might stall for a long time! */
|
||||
if (_this->hidden->audioQueue) {
|
||||
AudioQueueFlush(_this->hidden->audioQueue);
|
||||
AudioQueueStop(_this->hidden->audioQueue, 0);
|
||||
AudioQueueDispose(_this->hidden->audioQueue, 0);
|
||||
if (device->hidden->audioQueue) {
|
||||
AudioQueueFlush(device->hidden->audioQueue);
|
||||
AudioQueueStop(device->hidden->audioQueue, 0);
|
||||
AudioQueueDispose(device->hidden->audioQueue, 0);
|
||||
}
|
||||
|
||||
if (_this->hidden->thread) {
|
||||
SDL_assert(SDL_AtomicGet(&_this->shutdown) != 0); /* should have been set by SDL_audio.c */
|
||||
SDL_WaitThread(_this->hidden->thread, NULL);
|
||||
if (device->hidden->thread) {
|
||||
SDL_assert(SDL_AtomicGet(&device->shutdown) != 0); /* should have been set by SDL_audio.c */
|
||||
SDL_WaitThread(device->hidden->thread, NULL);
|
||||
}
|
||||
|
||||
if (iscapture) {
|
||||
@@ -707,11 +707,11 @@ static void COREAUDIO_CloseDevice(SDL_AudioDevice *_this)
|
||||
}
|
||||
|
||||
#ifndef MACOSX_COREAUDIO
|
||||
update_audio_session(_this, SDL_FALSE, SDL_TRUE);
|
||||
update_audio_session(device, SDL_FALSE, SDL_TRUE);
|
||||
#endif
|
||||
|
||||
for (i = 0; i < num_open_devices; ++i) {
|
||||
if (open_devices[i] == _this) {
|
||||
if (open_devices[i] == device) {
|
||||
--num_open_devices;
|
||||
if (i < num_open_devices) {
|
||||
SDL_memmove(&open_devices[i], &open_devices[i + 1], sizeof(open_devices[i]) * (num_open_devices - i));
|
||||
@@ -724,22 +724,22 @@ static void COREAUDIO_CloseDevice(SDL_AudioDevice *_this)
|
||||
open_devices = NULL;
|
||||
}
|
||||
|
||||
if (_this->hidden->ready_semaphore) {
|
||||
SDL_DestroySemaphore(_this->hidden->ready_semaphore);
|
||||
if (device->hidden->ready_semaphore) {
|
||||
SDL_DestroySemaphore(device->hidden->ready_semaphore);
|
||||
}
|
||||
|
||||
/* AudioQueueDispose() frees the actual buffer objects. */
|
||||
SDL_free(_this->hidden->audioBuffer);
|
||||
SDL_free(_this->hidden->thread_error);
|
||||
SDL_free(_this->hidden->buffer);
|
||||
SDL_free(_this->hidden);
|
||||
SDL_free(device->hidden->audioBuffer);
|
||||
SDL_free(device->hidden->thread_error);
|
||||
SDL_free(device->hidden->buffer);
|
||||
SDL_free(device->hidden);
|
||||
}
|
||||
|
||||
#ifdef MACOSX_COREAUDIO
|
||||
static int prepare_device(SDL_AudioDevice *_this)
|
||||
static int prepare_device(SDL_AudioDevice *device)
|
||||
{
|
||||
void *handle = _this->handle;
|
||||
SDL_bool iscapture = _this->iscapture;
|
||||
void *handle = device->handle;
|
||||
SDL_bool iscapture = device->iscapture;
|
||||
AudioDeviceID devid = (AudioDeviceID)((size_t)handle);
|
||||
OSStatus result = noErr;
|
||||
UInt32 size = 0;
|
||||
@@ -783,73 +783,73 @@ static int prepare_device(SDL_AudioDevice *_this)
|
||||
return 0;
|
||||
}
|
||||
|
||||
_this->hidden->deviceID = devid;
|
||||
device->hidden->deviceID = devid;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int assign_device_to_audioqueue(SDL_AudioDevice *_this)
|
||||
static int assign_device_to_audioqueue(SDL_AudioDevice *device)
|
||||
{
|
||||
const AudioObjectPropertyAddress prop = {
|
||||
kAudioDevicePropertyDeviceUID,
|
||||
_this->iscapture ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput,
|
||||
device->iscapture ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput,
|
||||
kAudioObjectPropertyElementMain
|
||||
};
|
||||
|
||||
OSStatus result;
|
||||
CFStringRef devuid;
|
||||
UInt32 devuidsize = sizeof(devuid);
|
||||
result = AudioObjectGetPropertyData(_this->hidden->deviceID, &prop, 0, NULL, &devuidsize, &devuid);
|
||||
result = AudioObjectGetPropertyData(device->hidden->deviceID, &prop, 0, NULL, &devuidsize, &devuid);
|
||||
CHECK_RESULT("AudioObjectGetPropertyData (kAudioDevicePropertyDeviceUID)");
|
||||
result = AudioQueueSetProperty(_this->hidden->audioQueue, kAudioQueueProperty_CurrentDevice, &devuid, devuidsize);
|
||||
result = AudioQueueSetProperty(device->hidden->audioQueue, kAudioQueueProperty_CurrentDevice, &devuid, devuidsize);
|
||||
CHECK_RESULT("AudioQueueSetProperty (kAudioQueueProperty_CurrentDevice)");
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int prepare_audioqueue(SDL_AudioDevice *_this)
|
||||
static int prepare_audioqueue(SDL_AudioDevice *device)
|
||||
{
|
||||
const AudioStreamBasicDescription *strdesc = &_this->hidden->strdesc;
|
||||
const int iscapture = _this->iscapture;
|
||||
const AudioStreamBasicDescription *strdesc = &device->hidden->strdesc;
|
||||
const int iscapture = device->iscapture;
|
||||
OSStatus result;
|
||||
int i, numAudioBuffers = 2;
|
||||
AudioChannelLayout layout;
|
||||
double MINIMUM_AUDIO_BUFFER_TIME_MS;
|
||||
const double msecs = (_this->spec.samples / ((double)_this->spec.freq)) * 1000.0;
|
||||
const double msecs = (device->spec.samples / ((double)device->spec.freq)) * 1000.0;
|
||||
;
|
||||
|
||||
SDL_assert(CFRunLoopGetCurrent() != NULL);
|
||||
|
||||
if (iscapture) {
|
||||
result = AudioQueueNewInput(strdesc, inputCallback, _this, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode, 0, &_this->hidden->audioQueue);
|
||||
result = AudioQueueNewInput(strdesc, inputCallback, device, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode, 0, &device->hidden->audioQueue);
|
||||
CHECK_RESULT("AudioQueueNewInput");
|
||||
} else {
|
||||
result = AudioQueueNewOutput(strdesc, outputCallback, _this, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode, 0, &_this->hidden->audioQueue);
|
||||
result = AudioQueueNewOutput(strdesc, outputCallback, device, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode, 0, &device->hidden->audioQueue);
|
||||
CHECK_RESULT("AudioQueueNewOutput");
|
||||
}
|
||||
|
||||
#ifdef MACOSX_COREAUDIO
|
||||
if (!assign_device_to_audioqueue(_this)) {
|
||||
if (!assign_device_to_audioqueue(device)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* only listen for unplugging on specific devices, not the default device, as that should
|
||||
switch to a different device (or hang out silently if there _is_ no other device). */
|
||||
if (_this->handle != NULL) {
|
||||
if (device->handle != NULL) {
|
||||
/* !!! FIXME: what does iOS do when a bluetooth audio device vanishes? Headphones unplugged? */
|
||||
/* !!! FIXME: (we only do a "default" device on iOS right now...can we do more?) */
|
||||
/* Fire a callback if the device stops being "alive" (disconnected, etc). */
|
||||
/* If this fails, oh well, we won't notice a device had an extraordinary event take place. */
|
||||
AudioObjectAddPropertyListener(_this->hidden->deviceID, &alive_address, device_unplugged, _this);
|
||||
AudioObjectAddPropertyListener(device->hidden->deviceID, &alive_address, device_unplugged, device);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Calculate the final parameters for this audio specification */
|
||||
SDL_CalculateAudioSpec(&_this->spec);
|
||||
SDL_CalculateAudioSpec(&device->spec);
|
||||
|
||||
/* Set the channel layout for the audio queue */
|
||||
SDL_zero(layout);
|
||||
switch (_this->spec.channels) {
|
||||
switch (device->spec.channels) {
|
||||
case 1:
|
||||
layout.mChannelLayoutTag = kAudioChannelLayoutTag_Mono;
|
||||
break;
|
||||
@@ -877,16 +877,16 @@ static int prepare_audioqueue(SDL_AudioDevice *_this)
|
||||
break;
|
||||
}
|
||||
if (layout.mChannelLayoutTag != 0) {
|
||||
result = AudioQueueSetProperty(_this->hidden->audioQueue, kAudioQueueProperty_ChannelLayout, &layout, sizeof(layout));
|
||||
result = AudioQueueSetProperty(device->hidden->audioQueue, kAudioQueueProperty_ChannelLayout, &layout, sizeof(layout));
|
||||
CHECK_RESULT("AudioQueueSetProperty(kAudioQueueProperty_ChannelLayout)");
|
||||
}
|
||||
|
||||
/* Allocate a sample buffer */
|
||||
_this->hidden->bufferSize = _this->spec.size;
|
||||
_this->hidden->bufferOffset = iscapture ? 0 : _this->hidden->bufferSize;
|
||||
device->hidden->bufferSize = device->spec.size;
|
||||
device->hidden->bufferOffset = iscapture ? 0 : device->hidden->bufferSize;
|
||||
|
||||
_this->hidden->buffer = SDL_malloc(_this->hidden->bufferSize);
|
||||
if (_this->hidden->buffer == NULL) {
|
||||
device->hidden->buffer = SDL_malloc(device->hidden->bufferSize);
|
||||
if (device->hidden->buffer == NULL) {
|
||||
SDL_OutOfMemory();
|
||||
return 0;
|
||||
}
|
||||
@@ -903,9 +903,9 @@ static int prepare_audioqueue(SDL_AudioDevice *_this)
|
||||
numAudioBuffers = ((int)SDL_ceil(MINIMUM_AUDIO_BUFFER_TIME_MS / msecs) * 2);
|
||||
}
|
||||
|
||||
_this->hidden->numAudioBuffers = numAudioBuffers;
|
||||
_this->hidden->audioBuffer = SDL_calloc(1, sizeof(AudioQueueBufferRef) * numAudioBuffers);
|
||||
if (_this->hidden->audioBuffer == NULL) {
|
||||
device->hidden->numAudioBuffers = numAudioBuffers;
|
||||
device->hidden->audioBuffer = SDL_calloc(1, sizeof(AudioQueueBufferRef) * numAudioBuffers);
|
||||
if (device->hidden->audioBuffer == NULL) {
|
||||
SDL_OutOfMemory();
|
||||
return 0;
|
||||
}
|
||||
@@ -915,16 +915,16 @@ static int prepare_audioqueue(SDL_AudioDevice *_this)
|
||||
#endif
|
||||
|
||||
for (i = 0; i < numAudioBuffers; i++) {
|
||||
result = AudioQueueAllocateBuffer(_this->hidden->audioQueue, _this->spec.size, &_this->hidden->audioBuffer[i]);
|
||||
result = AudioQueueAllocateBuffer(device->hidden->audioQueue, device->spec.size, &device->hidden->audioBuffer[i]);
|
||||
CHECK_RESULT("AudioQueueAllocateBuffer");
|
||||
SDL_memset(_this->hidden->audioBuffer[i]->mAudioData, _this->spec.silence, _this->hidden->audioBuffer[i]->mAudioDataBytesCapacity);
|
||||
_this->hidden->audioBuffer[i]->mAudioDataByteSize = _this->hidden->audioBuffer[i]->mAudioDataBytesCapacity;
|
||||
SDL_memset(device->hidden->audioBuffer[i]->mAudioData, device->spec.silence, device->hidden->audioBuffer[i]->mAudioDataBytesCapacity);
|
||||
device->hidden->audioBuffer[i]->mAudioDataByteSize = device->hidden->audioBuffer[i]->mAudioDataBytesCapacity;
|
||||
/* !!! FIXME: should we use AudioQueueEnqueueBufferWithParameters and specify all frames be "trimmed" so these are immediately ready to refill with SDL callback data? */
|
||||
result = AudioQueueEnqueueBuffer(_this->hidden->audioQueue, _this->hidden->audioBuffer[i], 0, NULL);
|
||||
result = AudioQueueEnqueueBuffer(device->hidden->audioQueue, device->hidden->audioBuffer[i], 0, NULL);
|
||||
CHECK_RESULT("AudioQueueEnqueueBuffer");
|
||||
}
|
||||
|
||||
result = AudioQueueStart(_this->hidden->audioQueue, NULL);
|
||||
result = AudioQueueStart(device->hidden->audioQueue, NULL);
|
||||
CHECK_RESULT("AudioQueueStart");
|
||||
|
||||
/* We're running! */
|
||||
@@ -933,41 +933,41 @@ static int prepare_audioqueue(SDL_AudioDevice *_this)
|
||||
|
||||
static int audioqueue_thread(void *arg)
|
||||
{
|
||||
SDL_AudioDevice *_this = (SDL_AudioDevice *)arg;
|
||||
SDL_AudioDevice *device = (SDL_AudioDevice *)arg;
|
||||
int rc;
|
||||
|
||||
#ifdef MACOSX_COREAUDIO
|
||||
const AudioObjectPropertyAddress default_device_address = {
|
||||
_this->iscapture ? kAudioHardwarePropertyDefaultInputDevice : kAudioHardwarePropertyDefaultOutputDevice,
|
||||
device->iscapture ? kAudioHardwarePropertyDefaultInputDevice : kAudioHardwarePropertyDefaultOutputDevice,
|
||||
kAudioObjectPropertyScopeGlobal,
|
||||
kAudioObjectPropertyElementMain
|
||||
};
|
||||
|
||||
if (_this->handle == NULL) { /* opened the default device? Register to know if the user picks a new default. */
|
||||
if (device->handle == NULL) { /* opened the default device? Register to know if the user picks a new default. */
|
||||
/* we don't care if this fails; we just won't change to new default devices, but we still otherwise function in this case. */
|
||||
AudioObjectAddPropertyListener(kAudioObjectSystemObject, &default_device_address, default_device_changed, _this);
|
||||
AudioObjectAddPropertyListener(kAudioObjectSystemObject, &default_device_address, default_device_changed, device);
|
||||
}
|
||||
#endif
|
||||
|
||||
rc = prepare_audioqueue(_this);
|
||||
rc = prepare_audioqueue(device);
|
||||
if (!rc) {
|
||||
_this->hidden->thread_error = SDL_strdup(SDL_GetError());
|
||||
SDL_PostSemaphore(_this->hidden->ready_semaphore);
|
||||
device->hidden->thread_error = SDL_strdup(SDL_GetError());
|
||||
SDL_PostSemaphore(device->hidden->ready_semaphore);
|
||||
return 0;
|
||||
}
|
||||
|
||||
SDL_SetThreadPriority(SDL_THREAD_PRIORITY_HIGH);
|
||||
|
||||
/* init was successful, alert parent thread and start running... */
|
||||
SDL_PostSemaphore(_this->hidden->ready_semaphore);
|
||||
SDL_PostSemaphore(device->hidden->ready_semaphore);
|
||||
|
||||
while (!SDL_AtomicGet(&_this->shutdown)) {
|
||||
while (!SDL_AtomicGet(&device->shutdown)) {
|
||||
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.10, 1);
|
||||
|
||||
#ifdef MACOSX_COREAUDIO
|
||||
if ((_this->handle == NULL) && SDL_AtomicGet(&_this->hidden->device_change_flag)) {
|
||||
const AudioDeviceID prev_devid = _this->hidden->deviceID;
|
||||
SDL_AtomicSet(&_this->hidden->device_change_flag, 0);
|
||||
if ((device->handle == NULL) && SDL_AtomicGet(&device->hidden->device_change_flag)) {
|
||||
const AudioDeviceID prev_devid = device->hidden->deviceID;
|
||||
SDL_AtomicSet(&device->hidden->device_change_flag, 0);
|
||||
|
||||
#if DEBUG_COREAUDIO
|
||||
printf("COREAUDIO: audioqueue_thread is trying to switch to new default device!\n");
|
||||
@@ -976,53 +976,53 @@ static int audioqueue_thread(void *arg)
|
||||
/* if any of this fails, there's not much to do but wait to see if the user gives up
|
||||
and quits (flagging the audioqueue for shutdown), or toggles to some other system
|
||||
output device (in which case we'll try again). */
|
||||
if (prepare_device(_this) && (prev_devid != _this->hidden->deviceID)) {
|
||||
AudioQueueStop(_this->hidden->audioQueue, 1);
|
||||
if (assign_device_to_audioqueue(_this)) {
|
||||
if (prepare_device(device) && (prev_devid != device->hidden->deviceID)) {
|
||||
AudioQueueStop(device->hidden->audioQueue, 1);
|
||||
if (assign_device_to_audioqueue(device)) {
|
||||
int i;
|
||||
for (i = 0; i < _this->hidden->numAudioBuffers; i++) {
|
||||
SDL_memset(_this->hidden->audioBuffer[i]->mAudioData, _this->spec.silence, _this->hidden->audioBuffer[i]->mAudioDataBytesCapacity);
|
||||
for (i = 0; i < device->hidden->numAudioBuffers; i++) {
|
||||
SDL_memset(device->hidden->audioBuffer[i]->mAudioData, device->spec.silence, device->hidden->audioBuffer[i]->mAudioDataBytesCapacity);
|
||||
/* !!! FIXME: should we use AudioQueueEnqueueBufferWithParameters and specify all frames be "trimmed" so these are immediately ready to refill with SDL callback data? */
|
||||
AudioQueueEnqueueBuffer(_this->hidden->audioQueue, _this->hidden->audioBuffer[i], 0, NULL);
|
||||
AudioQueueEnqueueBuffer(device->hidden->audioQueue, device->hidden->audioBuffer[i], 0, NULL);
|
||||
}
|
||||
AudioQueueStart(_this->hidden->audioQueue, NULL);
|
||||
AudioQueueStart(device->hidden->audioQueue, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!_this->iscapture) { /* Drain off any pending playback. */
|
||||
const CFTimeInterval secs = (((_this->spec.size / (SDL_AUDIO_BITSIZE(_this->spec.format) / 8.0)) / _this->spec.channels) / ((CFTimeInterval)_this->spec.freq)) * 2.0;
|
||||
if (!device->iscapture) { /* Drain off any pending playback. */
|
||||
const CFTimeInterval secs = (((device->spec.size / (SDL_AUDIO_BITSIZE(device->spec.format) / 8.0)) / device->spec.channels) / ((CFTimeInterval)device->spec.freq)) * 2.0;
|
||||
CFRunLoopRunInMode(kCFRunLoopDefaultMode, secs, 0);
|
||||
}
|
||||
|
||||
#ifdef MACOSX_COREAUDIO
|
||||
if (_this->handle == NULL) {
|
||||
if (device->handle == NULL) {
|
||||
/* we don't care if this fails; we just won't change to new default devices, but we still otherwise function in this case. */
|
||||
AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &default_device_address, default_device_changed, _this);
|
||||
AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &default_device_address, default_device_changed, device);
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int COREAUDIO_OpenDevice(SDL_AudioDevice *_this, const char *devname)
|
||||
static int COREAUDIO_OpenDevice(SDL_AudioDevice *device, const char *devname)
|
||||
{
|
||||
AudioStreamBasicDescription *strdesc;
|
||||
const SDL_AudioFormat *closefmts;
|
||||
SDL_AudioFormat test_format;
|
||||
SDL_bool iscapture = _this->iscapture;
|
||||
SDL_bool iscapture = device->iscapture;
|
||||
SDL_AudioDevice **new_open_devices;
|
||||
|
||||
/* Initialize all variables that we clean on shutdown */
|
||||
_this->hidden = (struct SDL_PrivateAudioData *)SDL_malloc(sizeof(*_this->hidden));
|
||||
if (_this->hidden == NULL) {
|
||||
device->hidden = (struct SDL_PrivateAudioData *)SDL_malloc(sizeof(*device->hidden));
|
||||
if (device->hidden == NULL) {
|
||||
return SDL_OutOfMemory();
|
||||
}
|
||||
SDL_zerop(_this->hidden);
|
||||
SDL_zerop(device->hidden);
|
||||
|
||||
strdesc = &_this->hidden->strdesc;
|
||||
strdesc = &device->hidden->strdesc;
|
||||
|
||||
if (iscapture) {
|
||||
open_capture_devices++;
|
||||
@@ -1033,26 +1033,26 @@ static int COREAUDIO_OpenDevice(SDL_AudioDevice *_this, const char *devname)
|
||||
new_open_devices = (SDL_AudioDevice **)SDL_realloc(open_devices, sizeof(open_devices[0]) * (num_open_devices + 1));
|
||||
if (new_open_devices) {
|
||||
open_devices = new_open_devices;
|
||||
open_devices[num_open_devices++] = _this;
|
||||
open_devices[num_open_devices++] = device;
|
||||
}
|
||||
|
||||
#ifndef MACOSX_COREAUDIO
|
||||
if (!update_audio_session(_this, SDL_TRUE, SDL_TRUE)) {
|
||||
if (!update_audio_session(device, SDL_TRUE, SDL_TRUE)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Stop CoreAudio from doing expensive audio rate conversion */
|
||||
@autoreleasepool {
|
||||
AVAudioSession *session = [AVAudioSession sharedInstance];
|
||||
[session setPreferredSampleRate:_this->spec.freq error:nil];
|
||||
_this->spec.freq = (int)session.sampleRate;
|
||||
[session setPreferredSampleRate:device->spec.freq error:nil];
|
||||
device->spec.freq = (int)session.sampleRate;
|
||||
#if TARGET_OS_TV
|
||||
if (iscapture) {
|
||||
[session setPreferredInputNumberOfChannels:_this->spec.channels error:nil];
|
||||
_this->spec.channels = session.preferredInputNumberOfChannels;
|
||||
[session setPreferredInputNumberOfChannels:device->spec.channels error:nil];
|
||||
device->spec.channels = session.preferredInputNumberOfChannels;
|
||||
} else {
|
||||
[session setPreferredOutputNumberOfChannels:_this->spec.channels error:nil];
|
||||
_this->spec.channels = session.preferredOutputNumberOfChannels;
|
||||
[session setPreferredOutputNumberOfChannels:device->spec.channels error:nil];
|
||||
device->spec.channels = session.preferredOutputNumberOfChannels;
|
||||
}
|
||||
#else
|
||||
/* Calling setPreferredOutputNumberOfChannels seems to break audio output on iOS */
|
||||
@@ -1064,11 +1064,11 @@ static int COREAUDIO_OpenDevice(SDL_AudioDevice *_this, const char *devname)
|
||||
SDL_zerop(strdesc);
|
||||
strdesc->mFormatID = kAudioFormatLinearPCM;
|
||||
strdesc->mFormatFlags = kLinearPCMFormatFlagIsPacked;
|
||||
strdesc->mChannelsPerFrame = _this->spec.channels;
|
||||
strdesc->mSampleRate = _this->spec.freq;
|
||||
strdesc->mChannelsPerFrame = device->spec.channels;
|
||||
strdesc->mSampleRate = device->spec.freq;
|
||||
strdesc->mFramesPerPacket = 1;
|
||||
|
||||
closefmts = SDL_ClosestAudioFormats(_this->spec.format);
|
||||
closefmts = SDL_ClosestAudioFormats(device->spec.format);
|
||||
while ((test_format = *(closefmts++)) != 0) {
|
||||
/* CoreAudio handles most of SDL's formats natively. */
|
||||
switch (test_format) {
|
||||
@@ -1091,7 +1091,7 @@ static int COREAUDIO_OpenDevice(SDL_AudioDevice *_this, const char *devname)
|
||||
if (!test_format) { /* shouldn't happen, but just in case... */
|
||||
return SDL_SetError("%s: Unsupported audio format", "coreaudio");
|
||||
}
|
||||
_this->spec.format = test_format;
|
||||
device->spec.format = test_format;
|
||||
strdesc->mBitsPerChannel = SDL_AUDIO_BITSIZE(test_format);
|
||||
if (SDL_AUDIO_ISBIGENDIAN(test_format)) {
|
||||
strdesc->mFormatFlags |= kLinearPCMFormatFlagIsBigEndian;
|
||||
@@ -1107,31 +1107,31 @@ static int COREAUDIO_OpenDevice(SDL_AudioDevice *_this, const char *devname)
|
||||
strdesc->mBytesPerPacket = strdesc->mBytesPerFrame * strdesc->mFramesPerPacket;
|
||||
|
||||
#ifdef MACOSX_COREAUDIO
|
||||
if (!prepare_device(_this)) {
|
||||
if (!prepare_device(device)) {
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* This has to init in a new thread so it can get its own CFRunLoop. :/ */
|
||||
_this->hidden->ready_semaphore = SDL_CreateSemaphore(0);
|
||||
if (!_this->hidden->ready_semaphore) {
|
||||
device->hidden->ready_semaphore = SDL_CreateSemaphore(0);
|
||||
if (!device->hidden->ready_semaphore) {
|
||||
return -1; /* oh well. */
|
||||
}
|
||||
|
||||
_this->hidden->thread = SDL_CreateThreadInternal(audioqueue_thread, "AudioQueue thread", 512 * 1024, _this);
|
||||
if (!_this->hidden->thread) {
|
||||
device->hidden->thread = SDL_CreateThreadInternal(audioqueue_thread, "AudioQueue thread", 512 * 1024, device);
|
||||
if (!device->hidden->thread) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
SDL_WaitSemaphore(_this->hidden->ready_semaphore);
|
||||
SDL_DestroySemaphore(_this->hidden->ready_semaphore);
|
||||
_this->hidden->ready_semaphore = NULL;
|
||||
SDL_WaitSemaphore(device->hidden->ready_semaphore);
|
||||
SDL_DestroySemaphore(device->hidden->ready_semaphore);
|
||||
device->hidden->ready_semaphore = NULL;
|
||||
|
||||
if ((_this->hidden->thread != NULL) && (_this->hidden->thread_error != NULL)) {
|
||||
return SDL_SetError("%s", _this->hidden->thread_error);
|
||||
if ((device->hidden->thread != NULL) && (device->hidden->thread_error != NULL)) {
|
||||
return SDL_SetError("%s", device->hidden->thread_error);
|
||||
}
|
||||
|
||||
return (_this->hidden->thread != NULL) ? 0 : -1;
|
||||
return (device->hidden->thread != NULL) ? 0 : -1;
|
||||
}
|
||||
|
||||
#ifndef MACOSX_COREAUDIO
|
||||
|
Reference in New Issue
Block a user