Core Audio output: Correctly terminate output when requested to stop, preventing a case where multiple outputs were draining the playback buffer at once

CQTexperiment
Christopher Snowhill 2022-01-12 16:04:41 -08:00
parent 2633e713a3
commit 8664bacc60
2 changed files with 14 additions and 2 deletions

View File

@ -20,6 +20,7 @@
@interface OutputCoreAudio : NSObject { @interface OutputCoreAudio : NSObject {
OutputNode * outputController; OutputNode * outputController;
BOOL running;
BOOL stopping; BOOL stopping;
BOOL stopped; BOOL stopped;

View File

@ -26,6 +26,7 @@ extern void scale_by_volume(float * buffer, size_t count, float volume);
volume = 1.0; volume = 1.0;
outputDeviceID = -1; outputDeviceID = -1;
listenerapplied = NO; listenerapplied = NO;
running = NO;
_sema = dispatch_semaphore_create(0); _sema = dispatch_semaphore_create(0);
@ -54,9 +55,11 @@ default_device_changed(AudioObjectID inObjectID, UInt32 inNumberAddresses, const
- (void)threadEntry:(id)arg - (void)threadEntry:(id)arg
{ {
running = YES;
while (!stopping) { while (!stopping) {
dispatch_semaphore_wait(_sema, DISPATCH_TIME_FOREVER); dispatch_semaphore_wait(_sema, DISPATCH_TIME_FOREVER);
} }
stopped = YES;
[self stop]; [self stop];
} }
@ -231,7 +234,9 @@ default_device_changed(AudioObjectID inObjectID, UInt32 inNumberAddresses, const
if (_au) if (_au)
[self stop]; [self stop];
running = NO;
stopping = NO; stopping = NO;
stopped = NO;
outputDeviceID = -1; outputDeviceID = -1;
AVAudioFormat *format, *renderFormat; AVAudioFormat *format, *renderFormat;
@ -326,7 +331,7 @@ default_device_changed(AudioObjectID inObjectID, UInt32 inNumberAddresses, const
amountToRead = inputData->mBuffers[0].mDataByteSize; amountToRead = inputData->mBuffers[0].mDataByteSize;
if (self->stopping == YES || [outputController endOfStream] == YES) if (self->stopping == YES || [outputController shouldContinue] == NO)
{ {
memset(readPointer, 0, amountToRead); memset(readPointer, 0, amountToRead);
self->stopping = YES; self->stopping = YES;
@ -381,6 +386,7 @@ default_device_changed(AudioObjectID inObjectID, UInt32 inNumberAddresses, const
- (void)stop - (void)stop
{ {
stopping = YES;
if (listenerapplied) { if (listenerapplied) {
AudioObjectPropertyAddress theAddress = { AudioObjectPropertyAddress theAddress = {
.mSelector = kAudioHardwarePropertyDefaultOutputDevice, .mSelector = kAudioHardwarePropertyDefaultOutputDevice,
@ -393,15 +399,20 @@ default_device_changed(AudioObjectID inObjectID, UInt32 inNumberAddresses, const
if (_au) { if (_au) {
[_au stopHardware]; [_au stopHardware];
_au = nil; _au = nil;
}
if (running)
while (!stopped)
{
stopping = YES; stopping = YES;
dispatch_semaphore_signal(_sema); dispatch_semaphore_signal(_sema);
usleep(500);
} }
} }
- (void)dealloc - (void)dealloc
{ {
[self stop]; [self stop];
[[NSUserDefaultsController sharedUserDefaultsController] removeObserver:self forKeyPath:@"values.outputDevice"]; [[NSUserDefaultsController sharedUserDefaultsController] removeObserver:self forKeyPath:@"values.outputDevice"];
} }