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:
parent
94fcb68563
commit
5424e18f27
17 changed files with 85 additions and 22 deletions
|
@ -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];
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -22,6 +22,8 @@
|
||||||
|
|
||||||
- (void)resetBuffer;
|
- (void)resetBuffer;
|
||||||
|
|
||||||
|
- (BOOL)paused;
|
||||||
|
|
||||||
- (void)process;
|
- (void)process;
|
||||||
- (AudioChunk * _Nullable)convert;
|
- (AudioChunk * _Nullable)convert;
|
||||||
|
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -21,6 +21,8 @@
|
||||||
|
|
||||||
- (void)resetBuffer;
|
- (void)resetBuffer;
|
||||||
|
|
||||||
|
- (BOOL)paused;
|
||||||
|
|
||||||
- (void)process;
|
- (void)process;
|
||||||
- (AudioChunk * _Nullable)convert;
|
- (AudioChunk * _Nullable)convert;
|
||||||
|
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -20,6 +20,8 @@
|
||||||
|
|
||||||
- (void)resetBuffer;
|
- (void)resetBuffer;
|
||||||
|
|
||||||
|
- (BOOL)paused;
|
||||||
|
|
||||||
- (void)process;
|
- (void)process;
|
||||||
- (AudioChunk * _Nullable)convert;
|
- (AudioChunk * _Nullable)convert;
|
||||||
|
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -22,6 +22,8 @@
|
||||||
|
|
||||||
- (void)resetBuffer;
|
- (void)resetBuffer;
|
||||||
|
|
||||||
|
- (BOOL)paused;
|
||||||
|
|
||||||
- (void)process;
|
- (void)process;
|
||||||
- (AudioChunk * _Nullable)convert;
|
- (AudioChunk * _Nullable)convert;
|
||||||
|
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -20,6 +20,8 @@
|
||||||
|
|
||||||
- (void)resetBuffer;
|
- (void)resetBuffer;
|
||||||
|
|
||||||
|
- (BOOL)paused;
|
||||||
|
|
||||||
- (void)process;
|
- (void)process;
|
||||||
- (AudioChunk * _Nullable)convert;
|
- (AudioChunk * _Nullable)convert;
|
||||||
|
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,8 @@
|
||||||
- (BOOL)setup;
|
- (BOOL)setup;
|
||||||
- (void)cleanUp;
|
- (void)cleanUp;
|
||||||
|
|
||||||
|
- (BOOL)paused;
|
||||||
|
|
||||||
- (void)resetBuffer;
|
- (void)resetBuffer;
|
||||||
|
|
||||||
- (void)pop;
|
- (void)pop;
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
Loading…
Reference in a new issue