Audio: Fix more hangs and resume playback on start

Check for paused processing state in various places, so that startup
playback works properly, and resume playback at seek offset works
properly and doesn't hang the player.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
This commit is contained in:
Christopher Snowhill 2025-02-13 22:25:27 -08:00
parent 94fcb68563
commit 5424e18f27
17 changed files with 85 additions and 22 deletions

View file

@ -569,7 +569,14 @@ static void convert_be_to_le(uint8_t *buffer, size_t bitsPerSample, size_t bytes
double streamTimestamp = 0.0; double streamTimestamp = 0.0;
double streamTimeRatio = 1.0; double streamTimeRatio = 1.0;
if (![self peekTimestamp:&streamTimestamp timeRatio:&streamTimeRatio]) { BOOL blocked = NO;
while(![self peekTimestamp:&streamTimestamp timeRatio:&streamTimeRatio]) {
if((blocked = block())) {
break;
}
}
if(blocked) {
inMerger = NO; inMerger = NO;
return [[AudioChunk alloc] init]; return [[AudioChunk alloc] init];
} }

View file

@ -73,6 +73,8 @@
- (BOOL)setupWithInputFormat:(AudioStreamBasicDescription)inputFormat withInputConfig:(uint32_t)inputConfig outputFormat:(AudioStreamBasicDescription)outputFormat isLossless:(BOOL)lossless; - (BOOL)setupWithInputFormat:(AudioStreamBasicDescription)inputFormat withInputConfig:(uint32_t)inputConfig outputFormat:(AudioStreamBasicDescription)outputFormat isLossless:(BOOL)lossless;
- (void)cleanUp; - (void)cleanUp;
- (BOOL)paused;
- (void)process; - (void)process;
- (AudioChunk *)convert; - (AudioChunk *)convert;

View file

@ -90,6 +90,10 @@ void scale_by_volume(float *buffer, size_t count, float volume) {
} }
} }
- (BOOL)paused {
return paused;
}
- (void)process { - (void)process {
// Removed endOfStream check from here, since we want to be able to flush the converter // Removed endOfStream check from here, since we want to be able to flush the converter
// when the end of stream is reached. Convert function instead processes what it can, // when the end of stream is reached. Convert function instead processes what it can,

View file

@ -22,6 +22,8 @@
- (void)resetBuffer; - (void)resetBuffer;
- (BOOL)paused;
- (void)process; - (void)process;
- (AudioChunk * _Nullable)convert; - (AudioChunk * _Nullable)convert;

View file

@ -77,7 +77,6 @@
usleep(500); usleep(500);
} }
[super resetBuffer]; [super resetBuffer];
[self fullShutdown];
paused = NO; paused = NO;
} }
@ -87,6 +86,10 @@
formatSet = YES; formatSet = YES;
} }
- (BOOL)paused {
return paused;
}
- (void)process { - (void)process {
while([self shouldContinue] == YES) { while([self shouldContinue] == YES) {
if(paused) { if(paused) {

View file

@ -21,6 +21,8 @@
- (void)resetBuffer; - (void)resetBuffer;
- (BOOL)paused;
- (void)process; - (void)process;
- (AudioChunk * _Nullable)convert; - (AudioChunk * _Nullable)convert;

View file

@ -315,6 +315,10 @@ static OSStatus eqRenderCallback(void *inRefCon, AudioUnitRenderActionFlags *ioA
paused = NO; paused = NO;
} }
- (BOOL)paused {
return paused;
}
- (void)process { - (void)process {
while([self shouldContinue] == YES) { while([self shouldContinue] == YES) {
if(paused) { if(paused) {

View file

@ -20,6 +20,8 @@
- (void)resetBuffer; - (void)resetBuffer;
- (BOOL)paused;
- (void)process; - (void)process;
- (AudioChunk * _Nullable)convert; - (AudioChunk * _Nullable)convert;

View file

@ -132,6 +132,10 @@ static void * kDSPFSurroundNodeContext = &kDSPFSurroundNodeContext;
paused = NO; paused = NO;
} }
- (BOOL)paused {
return paused;
}
- (void)process { - (void)process {
while([self shouldContinue] == YES) { while([self shouldContinue] == YES) {
if(paused) { if(paused) {

View file

@ -22,6 +22,8 @@
- (void)resetBuffer; - (void)resetBuffer;
- (BOOL)paused;
- (void)process; - (void)process;
- (AudioChunk * _Nullable)convert; - (AudioChunk * _Nullable)convert;

View file

@ -257,6 +257,10 @@ static void unregisterMotionListener(void) {
paused = NO; paused = NO;
} }
- (BOOL)paused {
return paused;
}
- (void)process { - (void)process {
while([self shouldContinue] == YES) { while([self shouldContinue] == YES) {
if(paused) { if(paused) {

View file

@ -20,6 +20,8 @@
- (void)resetBuffer; - (void)resetBuffer;
- (BOOL)paused;
- (void)process; - (void)process;
- (AudioChunk * _Nullable)convert; - (AudioChunk * _Nullable)convert;

View file

@ -338,6 +338,10 @@ static void * kDSPRubberbandNodeContext = &kDSPRubberbandNodeContext;
paused = NO; paused = NO;
} }
- (BOOL)paused {
return paused;
}
- (void)process { - (void)process {
while([self shouldContinue] == YES) { while([self shouldContinue] == YES) {
if(paused) { if(paused) {

View file

@ -46,6 +46,8 @@
- (void)cleanUp; - (void)cleanUp;
- (BOOL)paused;
- (void)writeData:(const void *_Nonnull)ptr amount:(size_t)a; - (void)writeData:(const void *_Nonnull)ptr amount:(size_t)a;
- (void)writeChunk:(AudioChunk *_Nonnull)chunk; - (void)writeChunk:(AudioChunk *_Nonnull)chunk;
- (AudioChunk *_Nonnull)readChunk:(size_t)maxFrames; - (AudioChunk *_Nonnull)readChunk:(size_t)maxFrames;

View file

@ -79,7 +79,7 @@
- (void)writeData:(const void *)ptr amount:(size_t)amount { - (void)writeData:(const void *)ptr amount:(size_t)amount {
inWrite = YES; inWrite = YES;
if(!shouldContinue) { if(!shouldContinue || [self paused]) {
inWrite = NO; inWrite = NO;
return; return;
} }
@ -105,7 +105,7 @@
} }
} }
while(shouldContinue == YES && durationLeft < 0.0) { while(shouldContinue == YES && ![self paused] && durationLeft < 0.0) {
if(durationLeft < 0.0 || shouldReset) { if(durationLeft < 0.0 || shouldReset) {
[accessLock unlock]; [accessLock unlock];
[writeSemaphore timedWait:2000]; [writeSemaphore timedWait:2000];
@ -132,7 +132,7 @@
- (void)writeChunk:(AudioChunk *)chunk { - (void)writeChunk:(AudioChunk *)chunk {
inWrite = YES; inWrite = YES;
if(!shouldContinue) { if(!shouldContinue || [self paused]) {
inWrite = NO; inWrite = NO;
return; return;
} }
@ -150,7 +150,7 @@
} }
} }
while(shouldContinue == YES && durationLeft < 0.0) { while(shouldContinue == YES && ![self paused] && durationLeft < 0.0) {
if(previousNode && [previousNode shouldContinue] == NO) { if(previousNode && [previousNode shouldContinue] == NO) {
shouldContinue = NO; shouldContinue = NO;
break; break;
@ -192,20 +192,22 @@
- (BOOL)peekFormat:(nonnull AudioStreamBasicDescription *)format channelConfig:(nonnull uint32_t *)config { - (BOOL)peekFormat:(nonnull AudioStreamBasicDescription *)format channelConfig:(nonnull uint32_t *)config {
inPeek = YES; inPeek = YES;
if(!shouldContinue) { if(!shouldContinue || [self paused]) {
inPeek = NO; inPeek = NO;
return NO; return NO;
} }
[accessLock lock]; [accessLock lock];
while(shouldContinue && [[previousNode buffer] isEmpty] && [previousNode endOfStream] == NO) { while(shouldContinue && ![self paused] &&
[[previousNode buffer] isEmpty] && [previousNode endOfStream] == NO) {
[accessLock unlock]; [accessLock unlock];
[writeSemaphore signal];
[[previousNode readSemaphore] timedWait:2000]; [[previousNode readSemaphore] timedWait:2000];
[accessLock lock]; [accessLock lock];
} }
if(!shouldContinue) { if(!shouldContinue || [self paused]) {
[accessLock unlock]; [accessLock unlock];
inPeek = NO; inPeek = NO;
return NO; return NO;
@ -229,20 +231,22 @@
- (BOOL)peekTimestamp:(double *_Nonnull)timestamp timeRatio:(double *_Nonnull)timeRatio { - (BOOL)peekTimestamp:(double *_Nonnull)timestamp timeRatio:(double *_Nonnull)timeRatio {
inPeek = YES; inPeek = YES;
if(!shouldContinue) { if(!shouldContinue || [self paused]) {
inPeek = NO; inPeek = NO;
return NO; return NO;
} }
[accessLock lock]; [accessLock lock];
while(shouldContinue && [[previousNode buffer] isEmpty] && [previousNode endOfStream] == NO) { while(shouldContinue && ![self paused] &&
[[previousNode buffer] isEmpty] && [previousNode endOfStream] == NO) {
[accessLock unlock]; [accessLock unlock];
[writeSemaphore signal];
[[previousNode readSemaphore] timedWait:2000]; [[previousNode readSemaphore] timedWait:2000];
[accessLock lock]; [accessLock lock];
} }
if(!shouldContinue) { if(!shouldContinue || [self paused]) {
[accessLock unlock]; [accessLock unlock];
inPeek = NO; inPeek = NO;
return NO; return NO;
@ -266,15 +270,17 @@
- (AudioChunk *)readChunk:(size_t)maxFrames { - (AudioChunk *)readChunk:(size_t)maxFrames {
inRead = YES; inRead = YES;
if(!shouldContinue) { if(!shouldContinue || [self paused]) {
inRead = NO; inRead = NO;
return [[AudioChunk alloc] init]; return [[AudioChunk alloc] init];
} }
[accessLock lock]; [accessLock lock];
while(shouldContinue && [[previousNode buffer] isEmpty] && [previousNode endOfStream] == NO) { while(shouldContinue && ![self paused] &&
[[previousNode buffer] isEmpty] && [previousNode endOfStream] == NO) {
[accessLock unlock]; [accessLock unlock];
[writeSemaphore signal];
[[previousNode readSemaphore] timedWait:2000]; [[previousNode readSemaphore] timedWait:2000];
[accessLock lock]; [accessLock lock];
if([previousNode shouldReset] == YES) { if([previousNode shouldReset] == YES) {
@ -282,7 +288,7 @@
} }
} }
if(!shouldContinue) { if(!shouldContinue || [self paused]) {
[accessLock unlock]; [accessLock unlock];
inRead = NO; inRead = NO;
return [[AudioChunk alloc] init]; return [[AudioChunk alloc] init];
@ -325,15 +331,17 @@
- (AudioChunk *)readChunkAsFloat32:(size_t)maxFrames { - (AudioChunk *)readChunkAsFloat32:(size_t)maxFrames {
inRead = YES; inRead = YES;
if(!shouldContinue) { if(!shouldContinue || [self paused]) {
inRead = NO; inRead = NO;
return [[AudioChunk alloc] init]; return [[AudioChunk alloc] init];
} }
[accessLock lock]; [accessLock lock];
while(shouldContinue && [[previousNode buffer] isEmpty] && [previousNode endOfStream] == NO) { while(shouldContinue && ![self paused] &&
[[previousNode buffer] isEmpty] && [previousNode endOfStream] == NO) {
[accessLock unlock]; [accessLock unlock];
[writeSemaphore signal];
[[previousNode readSemaphore] timedWait:2000]; [[previousNode readSemaphore] timedWait:2000];
[accessLock lock]; [accessLock lock];
if([previousNode shouldReset] == YES) { if([previousNode shouldReset] == YES) {
@ -341,7 +349,7 @@
} }
} }
if(!shouldContinue) { if(!shouldContinue || [self paused]) {
[accessLock unlock]; [accessLock unlock];
inRead = NO; inRead = NO;
return [[AudioChunk alloc] init]; return [[AudioChunk alloc] init];
@ -384,7 +392,7 @@
- (AudioChunk *)readAndMergeChunks:(size_t)maxFrames { - (AudioChunk *)readAndMergeChunks:(size_t)maxFrames {
inMerge = YES; inMerge = YES;
if(!shouldContinue) { if(!shouldContinue || [self paused]) {
inMerge = NO; inMerge = NO;
return [[AudioChunk alloc] init]; return [[AudioChunk alloc] init];
} }
@ -416,7 +424,7 @@
[[previousNode readSemaphore] timedWait:2000]; [[previousNode readSemaphore] timedWait:2000];
[accessLock lock]; [accessLock lock];
return !shouldContinue || ([[previousNode buffer] isEmpty] && [previousNode endOfStream] == YES); return !shouldContinue || [self paused] || ([[previousNode buffer] isEmpty] && [previousNode endOfStream] == YES);
}]; }];
} }
@ -433,7 +441,7 @@
- (AudioChunk *)readAndMergeChunksAsFloat32:(size_t)maxFrames { - (AudioChunk *)readAndMergeChunksAsFloat32:(size_t)maxFrames {
inMerge = YES; inMerge = YES;
if(!shouldContinue) { if(!shouldContinue || [self paused]) {
inMerge = NO; inMerge = NO;
return [[AudioChunk alloc] init]; return [[AudioChunk alloc] init];
} }
@ -465,7 +473,7 @@
[[previousNode readSemaphore] timedWait:2000]; [[previousNode readSemaphore] timedWait:2000];
[accessLock lock]; [accessLock lock];
return !shouldContinue || ([[previousNode buffer] isEmpty] && [previousNode endOfStream] == YES); return !shouldContinue || [self paused] || ([[previousNode buffer] isEmpty] && [previousNode endOfStream] == YES);
}]; }];
} }
@ -515,6 +523,11 @@
} }
} }
// Implementations should override
- (BOOL)paused {
return NO;
}
- (Semaphore *)writeSemaphore { - (Semaphore *)writeSemaphore {
return writeSemaphore; return writeSemaphore;
} }

View file

@ -20,6 +20,8 @@
- (BOOL)setup; - (BOOL)setup;
- (void)cleanUp; - (void)cleanUp;
- (BOOL)paused;
- (void)resetBuffer; - (void)resetBuffer;
- (void)pop; - (void)pop;

View file

@ -222,6 +222,10 @@ static VisualizationCollection *theCollection = nil;
downmixer = nil; downmixer = nil;
} }
- (BOOL)paused {
return paused;
}
- (void)process { - (void)process {
while([self shouldContinue] == YES) { while([self shouldContinue] == YES) {
if(paused) { if(paused) {