From d2e480ace53923554d171e5336ac9015333a6e77 Mon Sep 17 00:00:00 2001 From: Christopher Snowhill Date: Sun, 26 Dec 2021 17:16:16 -0800 Subject: [PATCH] Core Audio output: Properly support switching output devices --- Audio/Output/OutputCoreAudio.h | 3 +++ Audio/Output/OutputCoreAudio.m | 46 ++++++++++++++++++++++++++++++++-- 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/Audio/Output/OutputCoreAudio.h b/Audio/Output/OutputCoreAudio.h index ea08304e6..bb765c9df 100644 --- a/Audio/Output/OutputCoreAudio.h +++ b/Audio/Output/OutputCoreAudio.h @@ -18,7 +18,10 @@ @interface OutputCoreAudio : NSObject { OutputNode * outputController; + BOOL primed; + BOOL running; BOOL stopping; + BOOL stopped; float volume; diff --git a/Audio/Output/OutputCoreAudio.m b/Audio/Output/OutputCoreAudio.m index 33b7d3a44..6875a9d8f 100644 --- a/Audio/Output/OutputCoreAudio.m +++ b/Audio/Output/OutputCoreAudio.m @@ -11,6 +11,10 @@ #import "Logging.h" +@interface OutputCoreAudio (Private) +- (void)prime; +@end + @implementation OutputCoreAudio - (id)initWithController:(OutputNode *)c @@ -44,6 +48,7 @@ static void Sound_Renderer(void *userData, AudioQueueRef queue, AudioQueueBuffer if (output->stopping == YES) { + output->stopped = YES; return; } @@ -127,7 +132,15 @@ static void Sound_Renderer(void *userData, AudioQueueRef queue, AudioQueueBuffer return err; } + err = AudioQueueStop(audioQueue, true); + if (err) { + DLog(@"Error stopping stream to set device"); + return err; + } + primed = NO; err = AudioQueueSetProperty(audioQueue, kAudioQueueProperty_CurrentDevice, &theDeviceUID, sizeof(theDeviceUID)); + if (running) + [self start]; } else if (outputUnit) { err = AudioUnitSetProperty(outputUnit, @@ -258,6 +271,7 @@ static void Sound_Renderer(void *userData, AudioQueueRef queue, AudioQueueBuffer [self stop]; stopping = NO; + stopped = NO; AudioComponentDescription desc; OSStatus err; @@ -332,6 +346,19 @@ static void Sound_Renderer(void *userData, AudioQueueRef queue, AudioQueueBuffer if (err != noErr) return NO; + if (device) { + BOOL ok = [self setOutputDeviceWithDeviceDict:device]; + if (!ok) { + //Ruh roh. + [self setOutputDeviceWithDeviceDict:nil]; + + [[[NSUserDefaultsController sharedUserDefaultsController] defaults] removeObjectForKey:@"outputDevice"]; + } + } + else { + [self setOutputDeviceWithDeviceDict:nil]; + } + numberOfBuffers = 4; bufferByteSize = deviceFormat.mBytesPerPacket * 512; @@ -355,15 +382,22 @@ static void Sound_Renderer(void *userData, AudioQueueRef queue, AudioQueueBuffer } buffers[i]->mAudioDataByteSize = bufferByteSize; - - Sound_Renderer((__bridge void * _Nullable)(self), audioQueue, buffers[i]); } + [self prime]; + [outputController setFormat:&deviceFormat]; return (err == noErr); } +- (void)prime +{ + for (UInt32 i = 0; i < numberOfBuffers; ++i) + Sound_Renderer((__bridge void * _Nullable)(self), audioQueue, buffers[i]); + primed = YES; +} + - (void)setVolume:(double)v { volume = v * 0.01f; @@ -376,6 +410,9 @@ static void Sound_Renderer(void *userData, AudioQueueRef queue, AudioQueueBuffer AudioQueueSetParameter(audioQueue, kAudioQueueParam_VolumeRampTime, 0); AudioQueueSetParameter(audioQueue, kAudioQueueParam_Volume, volume); AudioQueueStart(audioQueue, NULL); + running = YES; + if (!primed) + [self prime]; } - (void)stop @@ -391,6 +428,7 @@ static void Sound_Renderer(void *userData, AudioQueueRef queue, AudioQueueBuffer { AudioQueuePause(audioQueue); AudioQueueStop(audioQueue, true); + running = NO; for (UInt32 i = 0; i < numberOfBuffers; ++i) { @@ -418,11 +456,15 @@ static void Sound_Renderer(void *userData, AudioQueueRef queue, AudioQueueBuffer - (void)pause { AudioQueuePause(audioQueue); + running = NO; } - (void)resume { AudioQueueStart(audioQueue, NULL); + running = YES; + if (!primed) + [self prime]; } @end