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>
181 lines
3.1 KiB
Objective-C
181 lines
3.1 KiB
Objective-C
//
|
|
// OutputNode.m
|
|
// Cog
|
|
//
|
|
// Created by Vincent Spader on 8/2/05.
|
|
// Copyright 2005 Vincent Spader. All rights reserved.
|
|
//
|
|
|
|
#import "OutputNode.h"
|
|
#import "OutputCoreAudio.h"
|
|
#import "AudioPlayer.h"
|
|
#import "BufferChain.h"
|
|
|
|
#import "Logging.h"
|
|
|
|
@implementation OutputNode
|
|
|
|
- (void)setup
|
|
{
|
|
amountPlayed = 0.0;
|
|
sampleRatio = 0.0;
|
|
|
|
paused = YES;
|
|
started = NO;
|
|
|
|
output = [[OutputCoreAudio alloc] initWithController:self];
|
|
|
|
[output setup];
|
|
}
|
|
|
|
- (void)seek:(double)time
|
|
{
|
|
// [output pause];
|
|
[self resetBuffer];
|
|
|
|
amountPlayed = time;
|
|
}
|
|
|
|
- (void)process
|
|
{
|
|
paused = NO;
|
|
[output start];
|
|
}
|
|
|
|
- (void)pause
|
|
{
|
|
paused = YES;
|
|
[output pause];
|
|
}
|
|
|
|
- (void)resume
|
|
{
|
|
paused = NO;
|
|
[output resume];
|
|
}
|
|
|
|
- (void)incrementAmountPlayed:(long)count
|
|
{
|
|
amountPlayed += (double)count * sampleRatio;
|
|
}
|
|
|
|
- (void)resetAmountPlayed
|
|
{
|
|
amountPlayed = 0;
|
|
}
|
|
|
|
- (void)endOfInputPlayed
|
|
{
|
|
[controller endOfInputPlayed];
|
|
}
|
|
|
|
- (BOOL)chainQueueHasTracks
|
|
{
|
|
return [controller chainQueueHasTracks];
|
|
}
|
|
|
|
- (double)secondsBuffered
|
|
{
|
|
return (double)([buffer bufferedLength]) / (format.mSampleRate * format.mBytesPerPacket);
|
|
}
|
|
|
|
- (int)readData:(void *)ptr amount:(int)amount
|
|
{
|
|
@autoreleasepool {
|
|
int n;
|
|
[self setPreviousNode:[[controller bufferChain] finalNode]];
|
|
|
|
n = [super readData:ptr amount:amount];
|
|
|
|
/* if (n == 0) {
|
|
DLog(@"Output Buffer dry!");
|
|
}
|
|
*/
|
|
|
|
return n;
|
|
}
|
|
}
|
|
|
|
- (double)amountPlayed
|
|
{
|
|
return amountPlayed;
|
|
}
|
|
|
|
- (AudioStreamBasicDescription) format
|
|
{
|
|
return format;
|
|
}
|
|
|
|
- (void)setFormat:(AudioStreamBasicDescription *)f
|
|
{
|
|
format = *f;
|
|
// Calculate a ratio and add to double(seconds) instead, as format may change
|
|
// double oldSampleRatio = sampleRatio;
|
|
sampleRatio = 1.0 / (format.mSampleRate * format.mBytesPerPacket);
|
|
BufferChain *bufferChain = [controller bufferChain];
|
|
if (bufferChain)
|
|
{
|
|
ConverterNode *converter = [bufferChain converter];
|
|
if (converter)
|
|
{
|
|
// This clears the resampler buffer, but not the input buffer
|
|
// We also have to jump the play position ahead accounting for
|
|
// the data we are flushing
|
|
#if 0
|
|
// We no longer need to do this, because outputchanged converter
|
|
// now uses the RefillNode to slap the previous samples into
|
|
// itself
|
|
if (oldSampleRatio)
|
|
amountPlayed += oldSampleRatio * [[converter buffer] bufferedLength];
|
|
#endif
|
|
[converter setOutputFormat:format];
|
|
[converter inputFormatDidChange:[bufferChain inputFormat]];
|
|
}
|
|
}
|
|
}
|
|
|
|
- (void)close
|
|
{
|
|
[output stop];
|
|
output = nil;
|
|
}
|
|
|
|
- (void)setVolume:(double) v
|
|
{
|
|
[output setVolume:v];
|
|
}
|
|
|
|
- (void)setShouldContinue:(BOOL)s
|
|
{
|
|
[super setShouldContinue:s];
|
|
|
|
// if (s == NO)
|
|
// [output stop];
|
|
}
|
|
|
|
- (BOOL)isPaused
|
|
{
|
|
return paused;
|
|
}
|
|
|
|
- (void)beginEqualizer:(AudioUnit)eq
|
|
{
|
|
[controller beginEqualizer:eq];
|
|
}
|
|
|
|
- (void)refreshEqualizer:(AudioUnit)eq
|
|
{
|
|
[controller refreshEqualizer:eq];
|
|
}
|
|
|
|
- (void)endEqualizer:(AudioUnit)eq
|
|
{
|
|
[controller endEqualizer:eq];
|
|
}
|
|
|
|
- (void)sustainHDCD
|
|
{
|
|
[output sustainHDCD];
|
|
}
|
|
|
|
@end
|