[Audio Output] Stop immediately, and fix deadlocks

Stop output when requested, except on natural completion of the last
track in the play queue. Also fix deadlocks with stopping and
restarting.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
swiftingly
Christopher Snowhill 2022-06-24 19:14:48 -07:00
parent 50b7390181
commit d2eb4af3d5
4 changed files with 38 additions and 19 deletions

View File

@ -62,9 +62,10 @@
[self waitUntilCallbacksExit]; [self waitUntilCallbacksExit];
if(output) { if(output) {
[output setShouldContinue:NO]; [output setShouldContinue:NO];
output = nil;
} }
output = [[OutputNode alloc] initWithController:self previous:nil]; if(!output) {
output = [[OutputNode alloc] initWithController:self previous:nil];
}
[output setup]; [output setup];
[output setVolume:volume]; [output setVolume:volume];
@synchronized(chainQueue) { @synchronized(chainQueue) {
@ -133,6 +134,9 @@
bufferChain = nil; bufferChain = nil;
} }
} }
if(output) {
[output setShouldContinue:NO];
}
output = nil; output = nil;
} }
@ -278,7 +282,7 @@
} }
- (void)endEqualizer:(AudioUnit)eq { - (void)endEqualizer:(AudioUnit)eq {
[self sendDelegateMethod:@selector(audioPlayer:removeEqualizer:) withVoid:eq waitUntilDone:YES]; [self sendDelegateMethod:@selector(audioPlayer:removeEqualizer:) withVoid:eq waitUntilDone:NO];
} }
- (void)addChainToQueue:(BufferChain *)newChain { - (void)addChainToQueue:(BufferChain *)newChain {

View File

@ -156,6 +156,10 @@
} }
- (void)setShouldContinue:(BOOL)s { - (void)setShouldContinue:(BOOL)s {
if(output && !s) {
[output stop];
}
[super setShouldContinue:s]; [super setShouldContinue:s];
// if (s == NO) // if (s == NO)

View File

@ -43,6 +43,7 @@ using std::atomic_long;
double lastVisRate; double lastVisRate;
BOOL stopInvoked; BOOL stopInvoked;
BOOL stopCompleted;
BOOL running; BOOL running;
BOOL stopping; BOOL stopping;
BOOL stopped; BOOL stopped;
@ -50,6 +51,7 @@ using std::atomic_long;
BOOL paused; BOOL paused;
BOOL restarted; BOOL restarted;
BOOL stopFlush; BOOL stopFlush;
BOOL commandStop;
BOOL eqEnabled; BOOL eqEnabled;
BOOL eqInitialized; BOOL eqInitialized;

View File

@ -212,20 +212,16 @@ static OSStatus eqRenderCallback(void *inRefCon, AudioUnitRenderActionFlags *ioA
return 0; return 0;
} }
if(stopping) return 0;
float volumeScale = 1.0; float volumeScale = 1.0;
double sustained; double sustained;
@synchronized(self) { sustained = secondsHdcdSustained;
sustained = secondsHdcdSustained;
}
if(sustained > 0) { if(sustained > 0) {
if(sustained < amountRead) { if(sustained < amountRead) {
@synchronized(self) { secondsHdcdSustained = 0;
secondsHdcdSustained = 0;
}
} else { } else {
@synchronized(self) { secondsHdcdSustained -= chunkDuration;
secondsHdcdSustained -= chunkDuration;
}
volumeScale = 0.5; volumeScale = 0.5;
} }
} }
@ -315,9 +311,8 @@ current_device_listener(AudioObjectID inObjectID, UInt32 inNumberAddresses, cons
} }
- (BOOL)processEndOfStream { - (BOOL)processEndOfStream {
if([outputController endOfStream] == YES && [self signalEndOfStream:secondsLatency]) { if(stopping || ([outputController endOfStream] == YES && [self signalEndOfStream:secondsLatency])) {
stopping = YES; stopping = YES;
stopFlush = YES;
return YES; return YES;
} }
return NO; return NO;
@ -378,7 +373,7 @@ current_device_listener(AudioObjectID inObjectID, UInt32 inNumberAddresses, cons
stopped = YES; stopped = YES;
if(!stopInvoked) { if(!stopInvoked) {
[self stop]; [self doStop];
} }
} }
@ -803,6 +798,8 @@ current_device_listener(AudioObjectID inObjectID, UInt32 inNumberAddresses, cons
@synchronized(self) { @synchronized(self) {
stopInvoked = NO; stopInvoked = NO;
stopCompleted = NO;
commandStop = NO;
running = NO; running = NO;
stopping = NO; stopping = NO;
@ -1000,8 +997,21 @@ current_device_listener(AudioObjectID inObjectID, UInt32 inNumberAddresses, cons
} }
- (void)stop { - (void)stop {
commandStop = YES;
[self doStop];
}
- (void)doStop {
if(stopInvoked) {
while(!stopCompleted) {
usleep(5000);
}
return;
}
@synchronized(self) { @synchronized(self) {
if(stopInvoked) return; if(commandStop) {
stopFlush = NO;
}
stopInvoked = YES; stopInvoked = YES;
if(observersapplied) { if(observersapplied) {
[[NSUserDefaultsController sharedUserDefaultsController] removeObserver:self forKeyPath:@"values.outputDevice" context:kOutputAVFoundationContext]; [[NSUserDefaultsController sharedUserDefaultsController] removeObserver:self forKeyPath:@"values.outputDevice" context:kOutputAVFoundationContext];
@ -1094,6 +1104,7 @@ current_device_listener(AudioObjectID inObjectID, UInt32 inNumberAddresses, cons
r8bstate_delete(r8bvis); r8bstate_delete(r8bvis);
r8bvis = NULL; r8bvis = NULL;
} }
stopCompleted = YES;
} }
} }
@ -1114,9 +1125,7 @@ current_device_listener(AudioObjectID inObjectID, UInt32 inNumberAddresses, cons
} }
- (void)sustainHDCD { - (void)sustainHDCD {
@synchronized(self) { secondsHdcdSustained = 10.0;
secondsHdcdSustained = 10.0;
}
} }
@end @end