Core Audio output: Properly support switching output devices

CQTexperiment
Christopher Snowhill 2021-12-26 17:16:16 -08:00
parent 642945e80a
commit d2e480ace5
2 changed files with 47 additions and 2 deletions

View File

@ -18,7 +18,10 @@
@interface OutputCoreAudio : NSObject { @interface OutputCoreAudio : NSObject {
OutputNode * outputController; OutputNode * outputController;
BOOL primed;
BOOL running;
BOOL stopping; BOOL stopping;
BOOL stopped;
float volume; float volume;

View File

@ -11,6 +11,10 @@
#import "Logging.h" #import "Logging.h"
@interface OutputCoreAudio (Private)
- (void)prime;
@end
@implementation OutputCoreAudio @implementation OutputCoreAudio
- (id)initWithController:(OutputNode *)c - (id)initWithController:(OutputNode *)c
@ -44,6 +48,7 @@ static void Sound_Renderer(void *userData, AudioQueueRef queue, AudioQueueBuffer
if (output->stopping == YES) if (output->stopping == YES)
{ {
output->stopped = YES;
return; return;
} }
@ -127,7 +132,15 @@ static void Sound_Renderer(void *userData, AudioQueueRef queue, AudioQueueBuffer
return err; 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)); err = AudioQueueSetProperty(audioQueue, kAudioQueueProperty_CurrentDevice, &theDeviceUID, sizeof(theDeviceUID));
if (running)
[self start];
} }
else if (outputUnit) { else if (outputUnit) {
err = AudioUnitSetProperty(outputUnit, err = AudioUnitSetProperty(outputUnit,
@ -258,6 +271,7 @@ static void Sound_Renderer(void *userData, AudioQueueRef queue, AudioQueueBuffer
[self stop]; [self stop];
stopping = NO; stopping = NO;
stopped = NO;
AudioComponentDescription desc; AudioComponentDescription desc;
OSStatus err; OSStatus err;
@ -332,6 +346,19 @@ static void Sound_Renderer(void *userData, AudioQueueRef queue, AudioQueueBuffer
if (err != noErr) if (err != noErr)
return NO; 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; numberOfBuffers = 4;
bufferByteSize = deviceFormat.mBytesPerPacket * 512; bufferByteSize = deviceFormat.mBytesPerPacket * 512;
@ -355,15 +382,22 @@ static void Sound_Renderer(void *userData, AudioQueueRef queue, AudioQueueBuffer
} }
buffers[i]->mAudioDataByteSize = bufferByteSize; buffers[i]->mAudioDataByteSize = bufferByteSize;
Sound_Renderer((__bridge void * _Nullable)(self), audioQueue, buffers[i]);
} }
[self prime];
[outputController setFormat:&deviceFormat]; [outputController setFormat:&deviceFormat];
return (err == noErr); 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 - (void)setVolume:(double)v
{ {
volume = v * 0.01f; 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_VolumeRampTime, 0);
AudioQueueSetParameter(audioQueue, kAudioQueueParam_Volume, volume); AudioQueueSetParameter(audioQueue, kAudioQueueParam_Volume, volume);
AudioQueueStart(audioQueue, NULL); AudioQueueStart(audioQueue, NULL);
running = YES;
if (!primed)
[self prime];
} }
- (void)stop - (void)stop
@ -391,6 +428,7 @@ static void Sound_Renderer(void *userData, AudioQueueRef queue, AudioQueueBuffer
{ {
AudioQueuePause(audioQueue); AudioQueuePause(audioQueue);
AudioQueueStop(audioQueue, true); AudioQueueStop(audioQueue, true);
running = NO;
for (UInt32 i = 0; i < numberOfBuffers; ++i) for (UInt32 i = 0; i < numberOfBuffers; ++i)
{ {
@ -418,11 +456,15 @@ static void Sound_Renderer(void *userData, AudioQueueRef queue, AudioQueueBuffer
- (void)pause - (void)pause
{ {
AudioQueuePause(audioQueue); AudioQueuePause(audioQueue);
running = NO;
} }
- (void)resume - (void)resume
{ {
AudioQueueStart(audioQueue, NULL); AudioQueueStart(audioQueue, NULL);
running = YES;
if (!primed)
[self prime];
} }
@end @end