Cog Audio: Dealt with a major retain cycle leak
This seals up a major memory leak of the playback state whenever a chain is released on stop or on manual track change. CogAudioMulti was retaining the input node due to its listeners, and InputNode was not releasing the listeners when asked to stop running. This is fixed now. Fixes #221 Signed-off-by: Christopher Snowhill <kode54@gmail.com>CQTexperiment
parent
77a079bd53
commit
9e5a70c9ae
|
@ -68,7 +68,10 @@
|
|||
ALog(@"Opening file for playback: %@ at seek offset %f%@", url, time, (paused) ? @", starting paused" : @"");
|
||||
|
||||
[self waitUntilCallbacksExit];
|
||||
output = nil;
|
||||
if (output) {
|
||||
[output setShouldContinue:NO];
|
||||
output = nil;
|
||||
}
|
||||
output = [[OutputNode alloc] initWithController:self previous:nil];
|
||||
[output setup];
|
||||
[output setVolume: volume];
|
||||
|
@ -135,6 +138,20 @@
|
|||
//Set shouldoContinue to NO on all things
|
||||
[self setShouldContinue:NO];
|
||||
[self setPlaybackStatus:CogStatusStopped waitUntilDone:YES];
|
||||
|
||||
@synchronized(chainQueue) {
|
||||
for (id anObject in chainQueue)
|
||||
{
|
||||
[anObject setShouldContinue:NO];
|
||||
}
|
||||
[chainQueue removeAllObjects];
|
||||
endOfInputReached = NO;
|
||||
if (bufferChain)
|
||||
{
|
||||
bufferChain = nil;
|
||||
}
|
||||
}
|
||||
output = nil;
|
||||
}
|
||||
|
||||
- (void)pause
|
||||
|
|
|
@ -28,6 +28,8 @@
|
|||
|
||||
BOOL shouldSeek;
|
||||
long seekFrame;
|
||||
|
||||
BOOL observersAdded;
|
||||
|
||||
Semaphore *exitAtTheEndOfTheStream;
|
||||
}
|
||||
|
|
|
@ -90,6 +90,8 @@
|
|||
forKeyPath:@"metadata"
|
||||
options:(NSKeyValueObservingOptionNew)
|
||||
context:NULL];
|
||||
|
||||
observersAdded = YES;
|
||||
}
|
||||
|
||||
- (void)observeValueForKeyPath:(NSString *)keyPath
|
||||
|
@ -219,8 +221,19 @@
|
|||
|
||||
- (void)removeObservers
|
||||
{
|
||||
[decoder removeObserver:self forKeyPath:@"properties"];
|
||||
[decoder removeObserver:self forKeyPath:@"metadata"];
|
||||
if (observersAdded)
|
||||
{
|
||||
[decoder removeObserver:self forKeyPath:@"properties"];
|
||||
[decoder removeObserver:self forKeyPath:@"metadata"];
|
||||
observersAdded = NO;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setShouldContinue:(BOOL)s
|
||||
{
|
||||
[super setShouldContinue:s];
|
||||
if (!s)
|
||||
[self removeObservers];
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
|
|
|
@ -137,6 +137,7 @@
|
|||
- (void)close
|
||||
{
|
||||
[output stop];
|
||||
output = nil;
|
||||
}
|
||||
|
||||
- (void)setVolume:(double) v
|
||||
|
|
|
@ -108,10 +108,11 @@ NSArray * sortClassesByPriority(NSArray * theClasses)
|
|||
- (void)close
|
||||
{
|
||||
if ( theDecoder != nil ) {
|
||||
[theDecoder close];
|
||||
for (NSDictionary *obsItem in cachedObservers) {
|
||||
[theDecoder removeObserver:[obsItem objectForKey:@"observer"] forKeyPath:[obsItem objectForKey:@"keyPath"]];
|
||||
}
|
||||
[cachedObservers removeAllObjects];
|
||||
[theDecoder close];
|
||||
theDecoder = nil;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,6 +46,7 @@
|
|||
atomic_long bytesHdcdSustained;
|
||||
|
||||
BOOL listenerapplied;
|
||||
BOOL observersapplied;
|
||||
|
||||
float volume;
|
||||
|
||||
|
|
|
@ -174,10 +174,7 @@ static OSStatus renderCallback( void *inRefCon, AudioUnitRenderActionFlags *ioAc
|
|||
#ifdef OUTPUT_LOG
|
||||
_logFile = fopen("/tmp/CogAudioLog.raw", "wb");
|
||||
#endif
|
||||
|
||||
[[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:@"values.outputDevice" options:0 context:NULL];
|
||||
[[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:@"values.GraphicEQenable" options:0 context:NULL];
|
||||
}
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
@ -704,6 +701,10 @@ default_device_changed(AudioObjectID inObjectID, UInt32 inNumberAddresses, const
|
|||
|
||||
[_au allocateRenderResourcesAndReturnError:&err];
|
||||
|
||||
[[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:@"values.outputDevice" options:0 context:NULL];
|
||||
[[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:@"values.GraphicEQenable" options:0 context:NULL];
|
||||
observersapplied = YES;
|
||||
|
||||
return (err == nil);
|
||||
}
|
||||
|
||||
|
@ -732,6 +733,12 @@ default_device_changed(AudioObjectID inObjectID, UInt32 inNumberAddresses, const
|
|||
|
||||
- (void)stop
|
||||
{
|
||||
stopInvoked = YES;
|
||||
if (observersapplied) {
|
||||
observersapplied = NO;
|
||||
[[NSUserDefaultsController sharedUserDefaultsController] removeObserver:self forKeyPath:@"values.outputDevice"];
|
||||
[[NSUserDefaultsController sharedUserDefaultsController] removeObserver:self forKeyPath:@"values.GraphicEQenable"];
|
||||
}
|
||||
if (stopNext && started && !paused) {
|
||||
while (![[outputController buffer] isEmpty]) {
|
||||
[writeSemaphore signal];
|
||||
|
@ -743,7 +750,6 @@ default_device_changed(AudioObjectID inObjectID, UInt32 inNumberAddresses, const
|
|||
stopNext = NO;
|
||||
[self signalEndOfStream];
|
||||
}
|
||||
stopInvoked = YES;
|
||||
stopping = YES;
|
||||
paused = NO;
|
||||
[writeSemaphore signal];
|
||||
|
@ -782,14 +788,13 @@ default_device_changed(AudioObjectID inObjectID, UInt32 inNumberAddresses, const
|
|||
_logFile = NULL;
|
||||
}
|
||||
#endif
|
||||
outputController = nil;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[self stop];
|
||||
|
||||
[[NSUserDefaultsController sharedUserDefaultsController] removeObserver:self forKeyPath:@"values.outputDevice"];
|
||||
[[NSUserDefaultsController sharedUserDefaultsController] removeObserver:self forKeyPath:@"values.GraphicEQenable"];
|
||||
if (!stopInvoked)
|
||||
[self stop];
|
||||
}
|
||||
|
||||
- (void)pause
|
||||
|
|
Loading…
Reference in New Issue