[Audio Player] Eliminate an avenue of lockups

Prevent the player from locking up in certain circumstances, by not
locking chainQueue the entire time this function is processing.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
lastfm
Christopher Snowhill 2022-07-05 00:53:55 -07:00
parent 42b2142ab7
commit 22cd16bb46
1 changed files with 47 additions and 41 deletions

View File

@ -357,71 +357,77 @@
return YES; return YES;
} }
BufferChain *lastChain;
@synchronized(chainQueue) { @synchronized(chainQueue) {
newChain = [[BufferChain alloc] initWithController:self]; newChain = [[BufferChain alloc] initWithController:self];
endOfInputReached = YES; endOfInputReached = YES;
BufferChain *lastChain = [chainQueue lastObject]; lastChain = [chainQueue lastObject];
if(lastChain == nil) { if(lastChain == nil) {
lastChain = bufferChain; lastChain = bufferChain;
} }
}
BOOL pathsEqual = NO; BOOL pathsEqual = NO;
if([nextStream isFileURL] && [[lastChain streamURL] isFileURL]) { if([nextStream isFileURL] && [[lastChain streamURL] isFileURL]) {
NSString *unixPathNext = [nextStream path]; NSString *unixPathNext = [nextStream path];
NSString *unixPathPrev = [[lastChain streamURL] path]; NSString *unixPathPrev = [[lastChain streamURL] path];
if([unixPathNext isEqualToString:unixPathPrev]) if([unixPathNext isEqualToString:unixPathPrev])
pathsEqual = YES; pathsEqual = YES;
} }
if(pathsEqual || ([[nextStream scheme] isEqualToString:[[lastChain streamURL] scheme]] && (([nextStream host] == nil && [[lastChain streamURL] host] == nil) || [[nextStream host] isEqualToString:[[lastChain streamURL] host]]) && [[nextStream path] isEqualToString:[[lastChain streamURL] path]])) { if(pathsEqual || ([[nextStream scheme] isEqualToString:[[lastChain streamURL] scheme]] && (([nextStream host] == nil && [[lastChain streamURL] host] == nil) || [[nextStream host] isEqualToString:[[lastChain streamURL] host]]) && [[nextStream path] isEqualToString:[[lastChain streamURL] path]])) {
if([lastChain setTrack:nextStream] && [newChain openWithInput:[lastChain inputNode] withUserInfo:nextStreamUserInfo withRGInfo:nextStreamRGInfo]) { if([lastChain setTrack:nextStream] && [newChain openWithInput:[lastChain inputNode] withUserInfo:nextStreamUserInfo withRGInfo:nextStreamRGInfo]) {
[newChain setStreamURL:nextStream]; [newChain setStreamURL:nextStream];
@synchronized(chainQueue) {
[self addChainToQueue:newChain]; [self addChainToQueue:newChain];
DLog(@"TRACK SET!!! %@", newChain);
// Keep on-playin
newChain = nil;
atomic_fetch_sub(&refCount, 1);
return NO;
} }
} DLog(@"TRACK SET!!! %@", newChain);
// Keep on-playin
lastChain = nil;
while(shouldContinue && ![newChain open:nextStream withUserInfo:nextStreamUserInfo withRGInfo:nextStreamRGInfo]) {
if(nextStream == nil) {
newChain = nil;
atomic_fetch_sub(&refCount, 1);
return YES;
}
newChain = nil; newChain = nil;
[self requestNextStream:nextStreamUserInfo];
newChain = [[BufferChain alloc] initWithController:self]; atomic_fetch_sub(&refCount, 1);
return NO;
} }
}
[self addChainToQueue:newChain]; lastChain = nil;
while(shouldContinue && ![newChain open:nextStream withUserInfo:nextStreamUserInfo withRGInfo:nextStreamRGInfo]) {
if(nextStream == nil) {
newChain = nil;
atomic_fetch_sub(&refCount, 1);
return YES;
}
newChain = nil; newChain = nil;
[self requestNextStream:nextStreamUserInfo];
// I'm stupid and can't hold too much stuff in my head all at once, so writing it here. newChain = [[BufferChain alloc] initWithController:self];
//
// Once we get here:
// - buffer chain for previous stream finished reading
// - there are (probably) some bytes of the previous stream in the output buffer which haven't been played
// (by output node) yet
// - self.bufferChain == previous playlist entry's buffer chain
// - self.nextStream == next playlist entry's URL
// - self.nextStreamUserInfo == next playlist entry
// - head of chainQueue is the buffer chain for the next entry (which has launched its threads already)
} }
@synchronized(chainQueue) {
[self addChainToQueue:newChain];
}
newChain = nil;
// I'm stupid and can't hold too much stuff in my head all at once, so writing it here.
//
// Once we get here:
// - buffer chain for previous stream finished reading
// - there are (probably) some bytes of the previous stream in the output buffer which haven't been played
// (by output node) yet
// - self.bufferChain == previous playlist entry's buffer chain
// - self.nextStream == next playlist entry's URL
// - self.nextStreamUserInfo == next playlist entry
// - head of chainQueue is the buffer chain for the next entry (which has launched its threads already)
atomic_fetch_sub(&refCount, 1); atomic_fetch_sub(&refCount, 1);
return YES; return YES;
} }