Audio: Improve buffer signaling
This should stop the deadlocks which were occurring. Signed-off-by: Christopher Snowhill <kode54@gmail.com>
This commit is contained in:
parent
4cd5cb8fa7
commit
b0e6ec98a9
13 changed files with 252 additions and 54 deletions
|
@ -201,7 +201,7 @@
|
||||||
- (void)dealloc {
|
- (void)dealloc {
|
||||||
[inputNode setShouldContinue:NO];
|
[inputNode setShouldContinue:NO];
|
||||||
[[inputNode exitAtTheEndOfTheStream] signal];
|
[[inputNode exitAtTheEndOfTheStream] signal];
|
||||||
[[inputNode semaphore] signal];
|
[[inputNode writeSemaphore] signal];
|
||||||
if(![inputNode threadExited])
|
if(![inputNode threadExited])
|
||||||
[[inputNode exitAtTheEndOfTheStream] wait]; // wait for decoder to be closed (see InputNode's -(void)process )
|
[[inputNode exitAtTheEndOfTheStream] wait]; // wait for decoder to be closed (see InputNode's -(void)process )
|
||||||
|
|
||||||
|
|
|
@ -459,7 +459,7 @@ static void convert_be_to_le(uint8_t *buffer, size_t bitsPerSample, size_t bytes
|
||||||
|
|
||||||
- (BOOL)isFull {
|
- (BOOL)isFull {
|
||||||
@synchronized (chunkList) {
|
@synchronized (chunkList) {
|
||||||
return (maxDuration - listDuration) < 0.05;
|
return (maxDuration - listDuration) < 0.001;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -588,7 +588,6 @@ static void convert_be_to_le(uint8_t *buffer, size_t bitsPerSample, size_t bytes
|
||||||
if(block()) {
|
if(block()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
usleep(500);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if(formatSet &&
|
if(formatSet &&
|
||||||
|
@ -608,7 +607,6 @@ static void convert_be_to_le(uint8_t *buffer, size_t bitsPerSample, size_t bytes
|
||||||
if(block()) {
|
if(block()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
usleep(500);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -482,6 +482,7 @@ static float db_to_scale(float db) {
|
||||||
|
|
||||||
paused = NO;
|
paused = NO;
|
||||||
[self cleanUp];
|
[self cleanUp];
|
||||||
|
[super cleanUp];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setOutputFormat:(AudioStreamBasicDescription)format {
|
- (void)setOutputFormat:(AudioStreamBasicDescription)format {
|
||||||
|
|
|
@ -38,6 +38,7 @@
|
||||||
- (void)dealloc {
|
- (void)dealloc {
|
||||||
DLog(@"Downmix dealloc");
|
DLog(@"Downmix dealloc");
|
||||||
[self cleanUp];
|
[self cleanUp];
|
||||||
|
[super cleanUp];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)fullInit {
|
- (BOOL)fullInit {
|
||||||
|
|
|
@ -157,6 +157,7 @@ static OSStatus eqRenderCallback(void *inRefCon, AudioUnitRenderActionFlags *ioA
|
||||||
DLog(@"Equalizer dealloc");
|
DLog(@"Equalizer dealloc");
|
||||||
[self cleanUp];
|
[self cleanUp];
|
||||||
[self removeObservers];
|
[self removeObservers];
|
||||||
|
[super cleanUp];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)addObservers {
|
- (void)addObservers {
|
||||||
|
|
|
@ -55,6 +55,7 @@ static void * kDSPFSurroundNodeContext = &kDSPFSurroundNodeContext;
|
||||||
DLog(@"FreeSurround dealloc");
|
DLog(@"FreeSurround dealloc");
|
||||||
[self cleanUp];
|
[self cleanUp];
|
||||||
[self removeObservers];
|
[self removeObservers];
|
||||||
|
[super cleanUp];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)addObservers {
|
- (void)addObservers {
|
||||||
|
|
|
@ -130,6 +130,7 @@ static void unregisterMotionListener(void) {
|
||||||
DLog(@"HRTF dealloc");
|
DLog(@"HRTF dealloc");
|
||||||
[self cleanUp];
|
[self cleanUp];
|
||||||
[self removeObservers];
|
[self removeObservers];
|
||||||
|
[super cleanUp];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)addObservers {
|
- (void)addObservers {
|
||||||
|
|
|
@ -65,6 +65,7 @@ static void * kDSPRubberbandNodeContext = &kDSPRubberbandNodeContext;
|
||||||
DLog(@"Rubber Band dealloc");
|
DLog(@"Rubber Band dealloc");
|
||||||
[self cleanUp];
|
[self cleanUp];
|
||||||
[self removeObservers];
|
[self removeObservers];
|
||||||
|
[super cleanUp];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)addObservers {
|
- (void)addObservers {
|
||||||
|
|
|
@ -16,7 +16,8 @@
|
||||||
if(self) {
|
if(self) {
|
||||||
buffer = [[ChunkList alloc] initWithMaximumDuration:latency];
|
buffer = [[ChunkList alloc] initWithMaximumDuration:latency];
|
||||||
|
|
||||||
semaphore = [[Semaphore alloc] init];
|
writeSemaphore = [[Semaphore alloc] init];
|
||||||
|
readSemaphore = [[Semaphore alloc] init];
|
||||||
|
|
||||||
accessLock = [[NSLock alloc] init];
|
accessLock = [[NSLock alloc] init];
|
||||||
|
|
||||||
|
@ -31,6 +32,11 @@
|
||||||
|
|
||||||
durationPrebuffer = latency * 0.25;
|
durationPrebuffer = latency * 0.25;
|
||||||
|
|
||||||
|
inWrite = NO;
|
||||||
|
inPeek = NO;
|
||||||
|
inRead = NO;
|
||||||
|
inMerge = NO;
|
||||||
|
|
||||||
[self setPreviousNode:p];
|
[self setPreviousNode:p];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -246,7 +246,7 @@ static void *kInputNodeContext = &kInputNodeContext;
|
||||||
seekFrame = frame;
|
seekFrame = frame;
|
||||||
shouldSeek = YES;
|
shouldSeek = YES;
|
||||||
DLog(@"Should seek!");
|
DLog(@"Should seek!");
|
||||||
[semaphore signal];
|
[writeSemaphore signal];
|
||||||
|
|
||||||
if(endOfStream) {
|
if(endOfStream) {
|
||||||
[exitAtTheEndOfTheStream signal];
|
[exitAtTheEndOfTheStream signal];
|
||||||
|
@ -280,6 +280,7 @@ static void *kInputNodeContext = &kInputNodeContext;
|
||||||
- (void)dealloc {
|
- (void)dealloc {
|
||||||
DLog(@"Input Node dealloc");
|
DLog(@"Input Node dealloc");
|
||||||
[self removeObservers];
|
[self removeObservers];
|
||||||
|
[super cleanUp];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSDictionary *)properties {
|
- (NSDictionary *)properties {
|
||||||
|
|
|
@ -17,7 +17,8 @@
|
||||||
|
|
||||||
@interface Node : NSObject {
|
@interface Node : NSObject {
|
||||||
ChunkList *buffer;
|
ChunkList *buffer;
|
||||||
Semaphore *semaphore;
|
Semaphore *writeSemaphore;
|
||||||
|
Semaphore *readSemaphore;
|
||||||
|
|
||||||
NSLock *accessLock;
|
NSLock *accessLock;
|
||||||
|
|
||||||
|
@ -26,6 +27,11 @@
|
||||||
|
|
||||||
BOOL shouldReset;
|
BOOL shouldReset;
|
||||||
|
|
||||||
|
BOOL inWrite;
|
||||||
|
BOOL inPeek;
|
||||||
|
BOOL inRead;
|
||||||
|
BOOL inMerge;
|
||||||
|
|
||||||
BOOL shouldContinue;
|
BOOL shouldContinue;
|
||||||
BOOL endOfStream; // All data is now in buffer
|
BOOL endOfStream; // All data is now in buffer
|
||||||
BOOL initialBufferFilled;
|
BOOL initialBufferFilled;
|
||||||
|
@ -38,6 +44,8 @@
|
||||||
}
|
}
|
||||||
- (id _Nullable)initWithController:(id _Nonnull)c previous:(id _Nullable)p;
|
- (id _Nullable)initWithController:(id _Nonnull)c previous:(id _Nullable)p;
|
||||||
|
|
||||||
|
- (void)cleanUp;
|
||||||
|
|
||||||
- (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;
|
||||||
|
@ -70,7 +78,8 @@
|
||||||
- (uint32_t)nodeChannelConfig;
|
- (uint32_t)nodeChannelConfig;
|
||||||
- (BOOL)nodeLossless;
|
- (BOOL)nodeLossless;
|
||||||
|
|
||||||
- (Semaphore *_Nonnull)semaphore;
|
- (Semaphore *_Nonnull)writeSemaphore;
|
||||||
|
- (Semaphore *_Nonnull)readSemaphore;
|
||||||
|
|
||||||
//-(void)resetBuffer;
|
//-(void)resetBuffer;
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,8 @@
|
||||||
self = [super init];
|
self = [super init];
|
||||||
if(self) {
|
if(self) {
|
||||||
buffer = [[ChunkList alloc] initWithMaximumDuration:10.0];
|
buffer = [[ChunkList alloc] initWithMaximumDuration:10.0];
|
||||||
semaphore = [[Semaphore alloc] init];
|
writeSemaphore = [[Semaphore alloc] init];
|
||||||
|
readSemaphore = [[Semaphore alloc] init];
|
||||||
|
|
||||||
accessLock = [[NSLock alloc] init];
|
accessLock = [[NSLock alloc] init];
|
||||||
|
|
||||||
|
@ -38,12 +39,32 @@
|
||||||
|
|
||||||
durationPrebuffer = 2.0;
|
durationPrebuffer = 2.0;
|
||||||
|
|
||||||
|
inWrite = NO;
|
||||||
|
inPeek = NO;
|
||||||
|
inRead = NO;
|
||||||
|
inMerge = NO;
|
||||||
|
|
||||||
[self setPreviousNode:p];
|
[self setPreviousNode:p];
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)dealloc {
|
||||||
|
[self cleanUp];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)cleanUp {
|
||||||
|
[self setShouldContinue:NO];
|
||||||
|
while(inWrite || inPeek || inRead || inMerge) {
|
||||||
|
[writeSemaphore signal];
|
||||||
|
if(previousNode) {
|
||||||
|
[[previousNode readSemaphore] signal];
|
||||||
|
}
|
||||||
|
usleep(500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
- (AudioStreamBasicDescription)nodeFormat {
|
- (AudioStreamBasicDescription)nodeFormat {
|
||||||
return nodeFormat;
|
return nodeFormat;
|
||||||
}
|
}
|
||||||
|
@ -57,6 +78,12 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)writeData:(const void *)ptr amount:(size_t)amount {
|
- (void)writeData:(const void *)ptr amount:(size_t)amount {
|
||||||
|
inWrite = YES;
|
||||||
|
if(!shouldContinue) {
|
||||||
|
inWrite = NO;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
[accessLock lock];
|
[accessLock lock];
|
||||||
|
|
||||||
AudioChunk *chunk = [[AudioChunk alloc] init];
|
AudioChunk *chunk = [[AudioChunk alloc] init];
|
||||||
|
@ -78,22 +105,38 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while(shouldContinue == YES && durationLeft <= 0.0) {
|
while(shouldContinue == YES && durationLeft < 0.0) {
|
||||||
if(durationLeft <= 0.0 || shouldReset) {
|
if(durationLeft < 0.0 || shouldReset) {
|
||||||
[accessLock unlock];
|
[accessLock unlock];
|
||||||
[semaphore wait];
|
[writeSemaphore timedWait:2000];
|
||||||
[accessLock lock];
|
[accessLock lock];
|
||||||
}
|
}
|
||||||
|
|
||||||
durationLeft = [buffer maxDuration] - [buffer listDuration];
|
durationLeft = [buffer maxDuration] - [buffer listDuration];
|
||||||
}
|
}
|
||||||
|
|
||||||
[buffer addChunk:chunk];
|
BOOL doSignal = NO;
|
||||||
|
if([chunk frameCount]) {
|
||||||
|
[buffer addChunk:chunk];
|
||||||
|
doSignal = YES;
|
||||||
|
}
|
||||||
|
|
||||||
[accessLock unlock];
|
[accessLock unlock];
|
||||||
|
|
||||||
|
if(doSignal) {
|
||||||
|
[readSemaphore signal];
|
||||||
|
}
|
||||||
|
|
||||||
|
inWrite = NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)writeChunk:(AudioChunk *)chunk {
|
- (void)writeChunk:(AudioChunk *)chunk {
|
||||||
|
inWrite = YES;
|
||||||
|
if(!shouldContinue) {
|
||||||
|
inWrite = NO;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
[accessLock lock];
|
[accessLock lock];
|
||||||
|
|
||||||
double durationList = [buffer listDuration];
|
double durationList = [buffer listDuration];
|
||||||
|
@ -107,24 +150,34 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while(shouldContinue == YES && durationLeft <= 0.0) {
|
while(shouldContinue == YES && durationLeft < 0.0) {
|
||||||
if(previousNode && [previousNode shouldContinue] == NO) {
|
if(previousNode && [previousNode shouldContinue] == NO) {
|
||||||
shouldContinue = NO;
|
shouldContinue = NO;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(durationLeft <= 0.0 || shouldReset) {
|
if(durationLeft < 0.0 || shouldReset) {
|
||||||
[accessLock unlock];
|
[accessLock unlock];
|
||||||
[semaphore wait];
|
[writeSemaphore timedWait:2000];
|
||||||
[accessLock lock];
|
[accessLock lock];
|
||||||
}
|
}
|
||||||
|
|
||||||
durationLeft = [buffer maxDuration] - [buffer listDuration];
|
durationLeft = [buffer maxDuration] - [buffer listDuration];
|
||||||
}
|
}
|
||||||
|
|
||||||
[buffer addChunk:chunk];
|
BOOL doSignal = NO;
|
||||||
|
if([chunk frameCount]) {
|
||||||
|
[buffer addChunk:chunk];
|
||||||
|
doSignal = YES;
|
||||||
|
}
|
||||||
|
|
||||||
[accessLock unlock];
|
[accessLock unlock];
|
||||||
|
|
||||||
|
if(doSignal) {
|
||||||
|
[readSemaphore signal];
|
||||||
|
}
|
||||||
|
|
||||||
|
inWrite = NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Should be overwriten by subclass.
|
// Should be overwriten by subclass.
|
||||||
|
@ -138,11 +191,30 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)peekFormat:(nonnull AudioStreamBasicDescription *)format channelConfig:(nonnull uint32_t *)config {
|
- (BOOL)peekFormat:(nonnull AudioStreamBasicDescription *)format channelConfig:(nonnull uint32_t *)config {
|
||||||
|
inPeek = YES;
|
||||||
|
if(!shouldContinue) {
|
||||||
|
inPeek = NO;
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
[accessLock lock];
|
[accessLock lock];
|
||||||
|
|
||||||
|
while(shouldContinue && [[previousNode buffer] isEmpty] && [previousNode endOfStream] == NO) {
|
||||||
|
[accessLock unlock];
|
||||||
|
[[previousNode readSemaphore] timedWait:2000];
|
||||||
|
[accessLock lock];
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!shouldContinue) {
|
||||||
|
[accessLock unlock];
|
||||||
|
inPeek = NO;
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
if([[previousNode buffer] isEmpty] && [previousNode endOfStream] == YES) {
|
if([[previousNode buffer] isEmpty] && [previousNode endOfStream] == YES) {
|
||||||
endOfStream = YES;
|
endOfStream = YES;
|
||||||
[accessLock unlock];
|
[accessLock unlock];
|
||||||
|
inPeek = NO;
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,15 +222,36 @@
|
||||||
|
|
||||||
[accessLock unlock];
|
[accessLock unlock];
|
||||||
|
|
||||||
|
inPeek = NO;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)peekTimestamp:(double *_Nonnull)timestamp timeRatio:(double *_Nonnull)timeRatio {
|
- (BOOL)peekTimestamp:(double *_Nonnull)timestamp timeRatio:(double *_Nonnull)timeRatio {
|
||||||
|
inPeek = YES;
|
||||||
|
if(!shouldContinue) {
|
||||||
|
inPeek = NO;
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
[accessLock lock];
|
[accessLock lock];
|
||||||
|
|
||||||
|
while(shouldContinue && [[previousNode buffer] isEmpty] && [previousNode endOfStream] == NO) {
|
||||||
|
[accessLock unlock];
|
||||||
|
[[previousNode readSemaphore] timedWait:2000];
|
||||||
|
[accessLock lock];
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!shouldContinue) {
|
||||||
|
[accessLock unlock];
|
||||||
|
inPeek = NO;
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
if([[previousNode buffer] isEmpty] && [previousNode endOfStream] == YES) {
|
if([[previousNode buffer] isEmpty] && [previousNode endOfStream] == YES) {
|
||||||
endOfStream = YES;
|
endOfStream = YES;
|
||||||
[accessLock unlock];
|
[accessLock unlock];
|
||||||
|
inPeek = NO;
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,15 +259,39 @@
|
||||||
|
|
||||||
[accessLock unlock];
|
[accessLock unlock];
|
||||||
|
|
||||||
|
inPeek = NO;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (AudioChunk *)readChunk:(size_t)maxFrames {
|
- (AudioChunk *)readChunk:(size_t)maxFrames {
|
||||||
|
inRead = YES;
|
||||||
|
if(!shouldContinue) {
|
||||||
|
inRead = NO;
|
||||||
|
return [[AudioChunk alloc] init];
|
||||||
|
}
|
||||||
|
|
||||||
[accessLock lock];
|
[accessLock lock];
|
||||||
|
|
||||||
|
while(shouldContinue && [[previousNode buffer] isEmpty] && [previousNode endOfStream] == NO) {
|
||||||
|
[accessLock unlock];
|
||||||
|
[[previousNode readSemaphore] timedWait:2000];
|
||||||
|
[accessLock lock];
|
||||||
|
if([previousNode shouldReset] == YES) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!shouldContinue) {
|
||||||
|
[accessLock unlock];
|
||||||
|
inRead = NO;
|
||||||
|
return [[AudioChunk alloc] init];
|
||||||
|
}
|
||||||
|
|
||||||
if([[previousNode buffer] isEmpty] && [previousNode endOfStream] == YES) {
|
if([[previousNode buffer] isEmpty] && [previousNode endOfStream] == YES) {
|
||||||
endOfStream = YES;
|
endOfStream = YES;
|
||||||
[accessLock unlock];
|
[accessLock unlock];
|
||||||
|
inRead = NO;
|
||||||
return [[AudioChunk alloc] init];
|
return [[AudioChunk alloc] init];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -186,7 +303,7 @@
|
||||||
shouldReset = YES;
|
shouldReset = YES;
|
||||||
[previousNode setShouldReset:NO];
|
[previousNode setShouldReset:NO];
|
||||||
|
|
||||||
[[previousNode semaphore] signal];
|
[[previousNode writeSemaphore] signal];
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioChunk *ret;
|
AudioChunk *ret;
|
||||||
|
@ -198,18 +315,42 @@
|
||||||
[accessLock unlock];
|
[accessLock unlock];
|
||||||
|
|
||||||
if([ret frameCount]) {
|
if([ret frameCount]) {
|
||||||
[[previousNode semaphore] signal];
|
[[previousNode writeSemaphore] signal];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inRead = NO;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (AudioChunk *)readChunkAsFloat32:(size_t)maxFrames {
|
- (AudioChunk *)readChunkAsFloat32:(size_t)maxFrames {
|
||||||
|
inRead = YES;
|
||||||
|
if(!shouldContinue) {
|
||||||
|
inRead = NO;
|
||||||
|
return [[AudioChunk alloc] init];
|
||||||
|
}
|
||||||
|
|
||||||
[accessLock lock];
|
[accessLock lock];
|
||||||
|
|
||||||
|
while(shouldContinue && [[previousNode buffer] isEmpty] && [previousNode endOfStream] == NO) {
|
||||||
|
[accessLock unlock];
|
||||||
|
[[previousNode readSemaphore] timedWait:2000];
|
||||||
|
[accessLock lock];
|
||||||
|
if([previousNode shouldReset] == YES) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!shouldContinue) {
|
||||||
|
[accessLock unlock];
|
||||||
|
inRead = NO;
|
||||||
|
return [[AudioChunk alloc] init];
|
||||||
|
}
|
||||||
|
|
||||||
if([[previousNode buffer] isEmpty] && [previousNode endOfStream] == YES) {
|
if([[previousNode buffer] isEmpty] && [previousNode endOfStream] == YES) {
|
||||||
endOfStream = YES;
|
endOfStream = YES;
|
||||||
[accessLock unlock];
|
[accessLock unlock];
|
||||||
|
inRead = NO;
|
||||||
return [[AudioChunk alloc] init];
|
return [[AudioChunk alloc] init];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -221,7 +362,7 @@
|
||||||
shouldReset = YES;
|
shouldReset = YES;
|
||||||
[previousNode setShouldReset:NO];
|
[previousNode setShouldReset:NO];
|
||||||
|
|
||||||
[[previousNode semaphore] signal];
|
[[previousNode writeSemaphore] signal];
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioChunk *ret;
|
AudioChunk *ret;
|
||||||
|
@ -233,83 +374,109 @@
|
||||||
[accessLock unlock];
|
[accessLock unlock];
|
||||||
|
|
||||||
if([ret frameCount]) {
|
if([ret frameCount]) {
|
||||||
[[previousNode semaphore] signal];
|
[[previousNode writeSemaphore] signal];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inRead = NO;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (AudioChunk *)readAndMergeChunks:(size_t)maxFrames {
|
- (AudioChunk *)readAndMergeChunks:(size_t)maxFrames {
|
||||||
|
inMerge = YES;
|
||||||
|
if(!shouldContinue) {
|
||||||
|
inMerge = NO;
|
||||||
|
return [[AudioChunk alloc] init];
|
||||||
|
}
|
||||||
|
|
||||||
[accessLock lock];
|
[accessLock lock];
|
||||||
|
|
||||||
if([[previousNode buffer] isEmpty] && [previousNode endOfStream] == YES) {
|
if([[previousNode buffer] isEmpty] && [previousNode endOfStream] == YES) {
|
||||||
endOfStream = YES;
|
endOfStream = YES;
|
||||||
[accessLock unlock];
|
[accessLock unlock];
|
||||||
|
inMerge = NO;
|
||||||
return [[AudioChunk alloc] init];
|
return [[AudioChunk alloc] init];
|
||||||
}
|
}
|
||||||
|
|
||||||
if([previousNode shouldReset] == YES) {
|
|
||||||
@autoreleasepool {
|
|
||||||
[buffer reset];
|
|
||||||
}
|
|
||||||
|
|
||||||
shouldReset = YES;
|
|
||||||
[previousNode setShouldReset:NO];
|
|
||||||
|
|
||||||
[[previousNode semaphore] signal];
|
|
||||||
}
|
|
||||||
|
|
||||||
[accessLock unlock];
|
|
||||||
|
|
||||||
AudioChunk *ret;
|
AudioChunk *ret;
|
||||||
|
|
||||||
@autoreleasepool {
|
@autoreleasepool {
|
||||||
ret = [[previousNode buffer] removeAndMergeSamples:maxFrames callBlock:^BOOL{
|
ret = [[previousNode buffer] removeAndMergeSamples:maxFrames callBlock:^BOOL{
|
||||||
return [[previousNode buffer] isEmpty] && [previousNode endOfStream] == YES;
|
if([previousNode shouldReset] == YES) {
|
||||||
|
@autoreleasepool {
|
||||||
|
[buffer reset];
|
||||||
|
}
|
||||||
|
|
||||||
|
shouldReset = YES;
|
||||||
|
[previousNode setShouldReset:NO];
|
||||||
|
}
|
||||||
|
|
||||||
|
[accessLock unlock];
|
||||||
|
[[previousNode writeSemaphore] signal];
|
||||||
|
[[previousNode readSemaphore] timedWait:2000];
|
||||||
|
[accessLock lock];
|
||||||
|
|
||||||
|
return !shouldContinue || ([[previousNode buffer] isEmpty] && [previousNode endOfStream] == YES);
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[accessLock unlock];
|
||||||
|
|
||||||
if([ret frameCount]) {
|
if([ret frameCount]) {
|
||||||
[[previousNode semaphore] signal];
|
[[previousNode writeSemaphore] signal];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inMerge = NO;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (AudioChunk *)readAndMergeChunksAsFloat32:(size_t)maxFrames {
|
- (AudioChunk *)readAndMergeChunksAsFloat32:(size_t)maxFrames {
|
||||||
|
inMerge = YES;
|
||||||
|
if(!shouldContinue) {
|
||||||
|
inMerge = NO;
|
||||||
|
return [[AudioChunk alloc] init];
|
||||||
|
}
|
||||||
|
|
||||||
[accessLock lock];
|
[accessLock lock];
|
||||||
|
|
||||||
if([[previousNode buffer] isEmpty] && [previousNode endOfStream] == YES) {
|
if([[previousNode buffer] isEmpty] && [previousNode endOfStream] == YES) {
|
||||||
endOfStream = YES;
|
endOfStream = YES;
|
||||||
[accessLock unlock];
|
[accessLock unlock];
|
||||||
|
inMerge = NO;
|
||||||
return [[AudioChunk alloc] init];
|
return [[AudioChunk alloc] init];
|
||||||
}
|
}
|
||||||
|
|
||||||
if([previousNode shouldReset] == YES) {
|
|
||||||
@autoreleasepool {
|
|
||||||
[buffer reset];
|
|
||||||
}
|
|
||||||
|
|
||||||
shouldReset = YES;
|
|
||||||
[previousNode setShouldReset:NO];
|
|
||||||
|
|
||||||
[[previousNode semaphore] signal];
|
|
||||||
}
|
|
||||||
|
|
||||||
[accessLock unlock];
|
|
||||||
|
|
||||||
AudioChunk *ret;
|
AudioChunk *ret;
|
||||||
|
|
||||||
@autoreleasepool {
|
@autoreleasepool {
|
||||||
ret = [[previousNode buffer] removeAndMergeSamplesAsFloat32:maxFrames callBlock:^BOOL{
|
ret = [[previousNode buffer] removeAndMergeSamplesAsFloat32:maxFrames callBlock:^BOOL{
|
||||||
return [[previousNode buffer] isEmpty] && [previousNode endOfStream] == YES;
|
if([previousNode shouldReset] == YES) {
|
||||||
|
@autoreleasepool {
|
||||||
|
[buffer reset];
|
||||||
|
}
|
||||||
|
|
||||||
|
shouldReset = YES;
|
||||||
|
[previousNode setShouldReset:NO];
|
||||||
|
}
|
||||||
|
|
||||||
|
[accessLock unlock];
|
||||||
|
[[previousNode writeSemaphore] signal];
|
||||||
|
[[previousNode readSemaphore] timedWait:2000];
|
||||||
|
[accessLock lock];
|
||||||
|
|
||||||
|
return !shouldContinue || ([[previousNode buffer] isEmpty] && [previousNode endOfStream] == YES);
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[accessLock unlock];
|
||||||
|
|
||||||
if([ret frameCount]) {
|
if([ret frameCount]) {
|
||||||
[[previousNode semaphore] signal];
|
[[previousNode writeSemaphore] signal];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inMerge = NO;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -348,8 +515,12 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (Semaphore *)semaphore {
|
- (Semaphore *)writeSemaphore {
|
||||||
return semaphore;
|
return writeSemaphore;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (Semaphore *)readSemaphore {
|
||||||
|
return readSemaphore;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)endOfStream {
|
- (BOOL)endOfStream {
|
||||||
|
|
|
@ -111,7 +111,8 @@ static VisualizationCollection *theCollection = nil;
|
||||||
if(self) {
|
if(self) {
|
||||||
buffer = [[ChunkList alloc] initWithMaximumDuration:latency];
|
buffer = [[ChunkList alloc] initWithMaximumDuration:latency];
|
||||||
|
|
||||||
semaphore = [[Semaphore alloc] init];
|
writeSemaphore = [[Semaphore alloc] init];
|
||||||
|
readSemaphore = [[Semaphore alloc] init];
|
||||||
|
|
||||||
accessLock = [[NSLock alloc] init];
|
accessLock = [[NSLock alloc] init];
|
||||||
|
|
||||||
|
@ -133,6 +134,11 @@ static VisualizationCollection *theCollection = nil;
|
||||||
replay = NO;
|
replay = NO;
|
||||||
prerollBuffer = [[NSMutableData alloc] init];
|
prerollBuffer = [[NSMutableData alloc] init];
|
||||||
|
|
||||||
|
inWrite = NO;
|
||||||
|
inPeek = NO;
|
||||||
|
inRead = NO;
|
||||||
|
inMerge = NO;
|
||||||
|
|
||||||
[self setPreviousNode:p];
|
[self setPreviousNode:p];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,6 +149,7 @@ static VisualizationCollection *theCollection = nil;
|
||||||
DLog(@"Visualization node dealloc");
|
DLog(@"Visualization node dealloc");
|
||||||
[self cleanUp];
|
[self cleanUp];
|
||||||
[self pop];
|
[self pop];
|
||||||
|
[super cleanUp];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)pop {
|
- (void)pop {
|
||||||
|
|
Loading…
Reference in a new issue