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 {
OutputNode * outputController;
BOOL running;
BOOL stopping;
BOOL stopped;

View File

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