diff --git a/Audio/Chain/ChunkList.m b/Audio/Chain/ChunkList.m index 0dd6de125..eeb1a6439 100644 --- a/Audio/Chain/ChunkList.m +++ b/Audio/Chain/ChunkList.m @@ -569,7 +569,14 @@ static void convert_be_to_le(uint8_t *buffer, size_t bitsPerSample, size_t bytes double streamTimestamp = 0.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; return [[AudioChunk alloc] init]; } diff --git a/Audio/Chain/ConverterNode.h b/Audio/Chain/ConverterNode.h index d5b02adfb..8977f1a43 100644 --- a/Audio/Chain/ConverterNode.h +++ b/Audio/Chain/ConverterNode.h @@ -73,6 +73,8 @@ - (BOOL)setupWithInputFormat:(AudioStreamBasicDescription)inputFormat withInputConfig:(uint32_t)inputConfig outputFormat:(AudioStreamBasicDescription)outputFormat isLossless:(BOOL)lossless; - (void)cleanUp; +- (BOOL)paused; + - (void)process; - (AudioChunk *)convert; diff --git a/Audio/Chain/ConverterNode.m b/Audio/Chain/ConverterNode.m index 00af5de23..3e4ac572c 100644 --- a/Audio/Chain/ConverterNode.m +++ b/Audio/Chain/ConverterNode.m @@ -90,6 +90,10 @@ void scale_by_volume(float *buffer, size_t count, float volume) { } } +- (BOOL)paused { + return paused; +} + - (void)process { // 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, diff --git a/Audio/Chain/DSP/DSPDownmixNode.h b/Audio/Chain/DSP/DSPDownmixNode.h index dc7915736..2db82b32c 100644 --- a/Audio/Chain/DSP/DSPDownmixNode.h +++ b/Audio/Chain/DSP/DSPDownmixNode.h @@ -22,6 +22,8 @@ - (void)resetBuffer; +- (BOOL)paused; + - (void)process; - (AudioChunk * _Nullable)convert; diff --git a/Audio/Chain/DSP/DSPDownmixNode.m b/Audio/Chain/DSP/DSPDownmixNode.m index e48adbcbe..eccae3838 100644 --- a/Audio/Chain/DSP/DSPDownmixNode.m +++ b/Audio/Chain/DSP/DSPDownmixNode.m @@ -77,7 +77,6 @@ usleep(500); } [super resetBuffer]; - [self fullShutdown]; paused = NO; } @@ -87,6 +86,10 @@ formatSet = YES; } +- (BOOL)paused { + return paused; +} + - (void)process { while([self shouldContinue] == YES) { if(paused) { diff --git a/Audio/Chain/DSP/DSPEqualizerNode.h b/Audio/Chain/DSP/DSPEqualizerNode.h index b51550e5a..c422765d6 100644 --- a/Audio/Chain/DSP/DSPEqualizerNode.h +++ b/Audio/Chain/DSP/DSPEqualizerNode.h @@ -21,6 +21,8 @@ - (void)resetBuffer; +- (BOOL)paused; + - (void)process; - (AudioChunk * _Nullable)convert; diff --git a/Audio/Chain/DSP/DSPEqualizerNode.m b/Audio/Chain/DSP/DSPEqualizerNode.m index 9b2115d00..597ffd104 100644 --- a/Audio/Chain/DSP/DSPEqualizerNode.m +++ b/Audio/Chain/DSP/DSPEqualizerNode.m @@ -315,6 +315,10 @@ static OSStatus eqRenderCallback(void *inRefCon, AudioUnitRenderActionFlags *ioA paused = NO; } +- (BOOL)paused { + return paused; +} + - (void)process { while([self shouldContinue] == YES) { if(paused) { diff --git a/Audio/Chain/DSP/DSPFSurroundNode.h b/Audio/Chain/DSP/DSPFSurroundNode.h index dc9a19c10..7bbd0e9e2 100644 --- a/Audio/Chain/DSP/DSPFSurroundNode.h +++ b/Audio/Chain/DSP/DSPFSurroundNode.h @@ -20,6 +20,8 @@ - (void)resetBuffer; +- (BOOL)paused; + - (void)process; - (AudioChunk * _Nullable)convert; diff --git a/Audio/Chain/DSP/DSPFSurroundNode.m b/Audio/Chain/DSP/DSPFSurroundNode.m index 0c676f2fa..7311b043f 100644 --- a/Audio/Chain/DSP/DSPFSurroundNode.m +++ b/Audio/Chain/DSP/DSPFSurroundNode.m @@ -132,6 +132,10 @@ static void * kDSPFSurroundNodeContext = &kDSPFSurroundNodeContext; paused = NO; } +- (BOOL)paused { + return paused; +} + - (void)process { while([self shouldContinue] == YES) { if(paused) { diff --git a/Audio/Chain/DSP/DSPHRTFNode.h b/Audio/Chain/DSP/DSPHRTFNode.h index fd65aac24..1906442ed 100644 --- a/Audio/Chain/DSP/DSPHRTFNode.h +++ b/Audio/Chain/DSP/DSPHRTFNode.h @@ -22,6 +22,8 @@ - (void)resetBuffer; +- (BOOL)paused; + - (void)process; - (AudioChunk * _Nullable)convert; diff --git a/Audio/Chain/DSP/DSPHRTFNode.m b/Audio/Chain/DSP/DSPHRTFNode.m index 3ba6d0092..bb169a7ef 100644 --- a/Audio/Chain/DSP/DSPHRTFNode.m +++ b/Audio/Chain/DSP/DSPHRTFNode.m @@ -257,6 +257,10 @@ static void unregisterMotionListener(void) { paused = NO; } +- (BOOL)paused { + return paused; +} + - (void)process { while([self shouldContinue] == YES) { if(paused) { diff --git a/Audio/Chain/DSP/DSPRubberbandNode.h b/Audio/Chain/DSP/DSPRubberbandNode.h index f32a76293..c9816d79f 100644 --- a/Audio/Chain/DSP/DSPRubberbandNode.h +++ b/Audio/Chain/DSP/DSPRubberbandNode.h @@ -20,6 +20,8 @@ - (void)resetBuffer; +- (BOOL)paused; + - (void)process; - (AudioChunk * _Nullable)convert; diff --git a/Audio/Chain/DSP/DSPRubberbandNode.m b/Audio/Chain/DSP/DSPRubberbandNode.m index dee87b5f0..641b49650 100644 --- a/Audio/Chain/DSP/DSPRubberbandNode.m +++ b/Audio/Chain/DSP/DSPRubberbandNode.m @@ -338,6 +338,10 @@ static void * kDSPRubberbandNodeContext = &kDSPRubberbandNodeContext; paused = NO; } +- (BOOL)paused { + return paused; +} + - (void)process { while([self shouldContinue] == YES) { if(paused) { diff --git a/Audio/Chain/Node.h b/Audio/Chain/Node.h index 48dbb7ac8..77a58a2a2 100644 --- a/Audio/Chain/Node.h +++ b/Audio/Chain/Node.h @@ -46,6 +46,8 @@ - (void)cleanUp; +- (BOOL)paused; + - (void)writeData:(const void *_Nonnull)ptr amount:(size_t)a; - (void)writeChunk:(AudioChunk *_Nonnull)chunk; - (AudioChunk *_Nonnull)readChunk:(size_t)maxFrames; diff --git a/Audio/Chain/Node.m b/Audio/Chain/Node.m index fc402b3c6..dfdeffaf2 100644 --- a/Audio/Chain/Node.m +++ b/Audio/Chain/Node.m @@ -79,7 +79,7 @@ - (void)writeData:(const void *)ptr amount:(size_t)amount { inWrite = YES; - if(!shouldContinue) { + if(!shouldContinue || [self paused]) { inWrite = NO; return; } @@ -105,7 +105,7 @@ } } - while(shouldContinue == YES && durationLeft < 0.0) { + while(shouldContinue == YES && ![self paused] && durationLeft < 0.0) { if(durationLeft < 0.0 || shouldReset) { [accessLock unlock]; [writeSemaphore timedWait:2000]; @@ -132,7 +132,7 @@ - (void)writeChunk:(AudioChunk *)chunk { inWrite = YES; - if(!shouldContinue) { + if(!shouldContinue || [self paused]) { inWrite = NO; return; } @@ -150,7 +150,7 @@ } } - while(shouldContinue == YES && durationLeft < 0.0) { + while(shouldContinue == YES && ![self paused] && durationLeft < 0.0) { if(previousNode && [previousNode shouldContinue] == NO) { shouldContinue = NO; break; @@ -192,20 +192,22 @@ - (BOOL)peekFormat:(nonnull AudioStreamBasicDescription *)format channelConfig:(nonnull uint32_t *)config { inPeek = YES; - if(!shouldContinue) { + if(!shouldContinue || [self paused]) { inPeek = NO; return NO; } [accessLock lock]; - while(shouldContinue && [[previousNode buffer] isEmpty] && [previousNode endOfStream] == NO) { + while(shouldContinue && ![self paused] && + [[previousNode buffer] isEmpty] && [previousNode endOfStream] == NO) { [accessLock unlock]; + [writeSemaphore signal]; [[previousNode readSemaphore] timedWait:2000]; [accessLock lock]; } - if(!shouldContinue) { + if(!shouldContinue || [self paused]) { [accessLock unlock]; inPeek = NO; return NO; @@ -229,20 +231,22 @@ - (BOOL)peekTimestamp:(double *_Nonnull)timestamp timeRatio:(double *_Nonnull)timeRatio { inPeek = YES; - if(!shouldContinue) { + if(!shouldContinue || [self paused]) { inPeek = NO; return NO; } [accessLock lock]; - while(shouldContinue && [[previousNode buffer] isEmpty] && [previousNode endOfStream] == NO) { + while(shouldContinue && ![self paused] && + [[previousNode buffer] isEmpty] && [previousNode endOfStream] == NO) { [accessLock unlock]; + [writeSemaphore signal]; [[previousNode readSemaphore] timedWait:2000]; [accessLock lock]; } - if(!shouldContinue) { + if(!shouldContinue || [self paused]) { [accessLock unlock]; inPeek = NO; return NO; @@ -266,15 +270,17 @@ - (AudioChunk *)readChunk:(size_t)maxFrames { inRead = YES; - if(!shouldContinue) { + if(!shouldContinue || [self paused]) { inRead = NO; return [[AudioChunk alloc] init]; } [accessLock lock]; - while(shouldContinue && [[previousNode buffer] isEmpty] && [previousNode endOfStream] == NO) { + while(shouldContinue && ![self paused] && + [[previousNode buffer] isEmpty] && [previousNode endOfStream] == NO) { [accessLock unlock]; + [writeSemaphore signal]; [[previousNode readSemaphore] timedWait:2000]; [accessLock lock]; if([previousNode shouldReset] == YES) { @@ -282,7 +288,7 @@ } } - if(!shouldContinue) { + if(!shouldContinue || [self paused]) { [accessLock unlock]; inRead = NO; return [[AudioChunk alloc] init]; @@ -325,15 +331,17 @@ - (AudioChunk *)readChunkAsFloat32:(size_t)maxFrames { inRead = YES; - if(!shouldContinue) { + if(!shouldContinue || [self paused]) { inRead = NO; return [[AudioChunk alloc] init]; } [accessLock lock]; - while(shouldContinue && [[previousNode buffer] isEmpty] && [previousNode endOfStream] == NO) { + while(shouldContinue && ![self paused] && + [[previousNode buffer] isEmpty] && [previousNode endOfStream] == NO) { [accessLock unlock]; + [writeSemaphore signal]; [[previousNode readSemaphore] timedWait:2000]; [accessLock lock]; if([previousNode shouldReset] == YES) { @@ -341,7 +349,7 @@ } } - if(!shouldContinue) { + if(!shouldContinue || [self paused]) { [accessLock unlock]; inRead = NO; return [[AudioChunk alloc] init]; @@ -384,7 +392,7 @@ - (AudioChunk *)readAndMergeChunks:(size_t)maxFrames { inMerge = YES; - if(!shouldContinue) { + if(!shouldContinue || [self paused]) { inMerge = NO; return [[AudioChunk alloc] init]; } @@ -416,7 +424,7 @@ [[previousNode readSemaphore] timedWait:2000]; [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 { inMerge = YES; - if(!shouldContinue) { + if(!shouldContinue || [self paused]) { inMerge = NO; return [[AudioChunk alloc] init]; } @@ -465,7 +473,7 @@ [[previousNode readSemaphore] timedWait:2000]; [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 { return writeSemaphore; } diff --git a/Audio/Chain/VisualizationNode.h b/Audio/Chain/VisualizationNode.h index 6ff4b0a86..4ec90e4c7 100644 --- a/Audio/Chain/VisualizationNode.h +++ b/Audio/Chain/VisualizationNode.h @@ -20,6 +20,8 @@ - (BOOL)setup; - (void)cleanUp; +- (BOOL)paused; + - (void)resetBuffer; - (void)pop; diff --git a/Audio/Chain/VisualizationNode.m b/Audio/Chain/VisualizationNode.m index a57971ed9..2ade0c51d 100644 --- a/Audio/Chain/VisualizationNode.m +++ b/Audio/Chain/VisualizationNode.m @@ -222,6 +222,10 @@ static VisualizationCollection *theCollection = nil; downmixer = nil; } +- (BOOL)paused { + return paused; +} + - (void)process { while([self shouldContinue] == YES) { if(paused) {