Cog Audio: Fix memory leaks with new buffering
By applying copious amounts of autorelease pools, memory is freed in a timely manner. Prior to this, buffer objects were freed, but not being released, and thus accumulating in memory indefinitely, as the original threads and functions had autorelease pools that scoped the entire thread, rather than individual function blocks that utilized the new buffering system. This fixes memory growth caused by playback. Signed-off-by: Christopher Snowhill <kode54@gmail.com>
This commit is contained in:
parent
6120fce40a
commit
acb1dd75d3
4 changed files with 117 additions and 96 deletions
|
@ -49,7 +49,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)isFull {
|
- (BOOL)isFull {
|
||||||
return listDuration >= maxDuration;
|
return (maxDuration - listDuration) < 0.01;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)addChunk:(AudioChunk *)chunk {
|
- (void)addChunk:(AudioChunk *)chunk {
|
||||||
|
|
|
@ -422,7 +422,10 @@ static void convert_be_to_le(uint8_t *buffer, size_t bitsPerSample, size_t bytes
|
||||||
// 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,
|
||||||
// and returns 0 samples when it has nothing more to process at the end of stream.
|
// and returns 0 samples when it has nothing more to process at the end of stream.
|
||||||
while([self shouldContinue] == YES) {
|
while([self shouldContinue] == YES) {
|
||||||
int amountConverted = [self convert:writeBuf amount:CHUNK_SIZE];
|
int amountConverted;
|
||||||
|
@autoreleasepool {
|
||||||
|
amountConverted = [self convert:writeBuf amount:CHUNK_SIZE];
|
||||||
|
}
|
||||||
if(!amountConverted) {
|
if(!amountConverted) {
|
||||||
if(paused) {
|
if(paused) {
|
||||||
while(paused)
|
while(paused)
|
||||||
|
@ -985,6 +988,7 @@ static float db_to_scale(float db) {
|
||||||
[refillNode setChannelConfig:previousOutputConfig];
|
[refillNode setChannelConfig:previousOutputConfig];
|
||||||
|
|
||||||
for(;;) {
|
for(;;) {
|
||||||
|
@autoreleasepool {
|
||||||
AudioChunk *chunk = [buffer removeSamples:16384];
|
AudioChunk *chunk = [buffer removeSamples:16384];
|
||||||
size_t frameCount = [chunk frameCount];
|
size_t frameCount = [chunk frameCount];
|
||||||
if(frameCount) {
|
if(frameCount) {
|
||||||
|
@ -993,6 +997,7 @@ static float db_to_scale(float db) {
|
||||||
} else
|
} else
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[self setupWithInputFormat:previousOutputFormat withInputConfig:[AudioChunk guessChannelConfig:previousOutputFormat.mChannelsPerFrame] outputFormat:outputFormat outputConfig:outputChannelConfig isLossless:rememberedLossless];
|
[self setupWithInputFormat:previousOutputFormat withInputConfig:[AudioChunk guessChannelConfig:previousOutputFormat.mChannelsPerFrame] outputFormat:outputFormat outputConfig:outputChannelConfig isLossless:rememberedLossless];
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -105,7 +105,9 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
if([previousNode shouldReset] == YES) {
|
if([previousNode shouldReset] == YES) {
|
||||||
|
@autoreleasepool {
|
||||||
[buffer reset];
|
[buffer reset];
|
||||||
|
}
|
||||||
|
|
||||||
shouldReset = YES;
|
shouldReset = YES;
|
||||||
[previousNode setShouldReset:NO];
|
[previousNode setShouldReset:NO];
|
||||||
|
@ -113,7 +115,11 @@
|
||||||
[[previousNode semaphore] signal];
|
[[previousNode semaphore] signal];
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioChunk *ret = [[previousNode buffer] removeSamples:maxFrames];
|
AudioChunk *ret;
|
||||||
|
|
||||||
|
@autoreleasepool {
|
||||||
|
ret = [[previousNode buffer] removeSamples:maxFrames];
|
||||||
|
}
|
||||||
|
|
||||||
[accessLock unlock];
|
[accessLock unlock];
|
||||||
|
|
||||||
|
@ -151,10 +157,12 @@
|
||||||
- (void)resetBuffer {
|
- (void)resetBuffer {
|
||||||
shouldReset = YES; // Will reset on next write.
|
shouldReset = YES; // Will reset on next write.
|
||||||
if(previousNode == nil) {
|
if(previousNode == nil) {
|
||||||
|
@autoreleasepool {
|
||||||
[accessLock lock];
|
[accessLock lock];
|
||||||
[buffer reset];
|
[buffer reset];
|
||||||
[accessLock unlock];
|
[accessLock unlock];
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (Semaphore *)semaphore {
|
- (Semaphore *)semaphore {
|
||||||
|
|
|
@ -48,6 +48,7 @@ static void scaleBuffersByVolume(AudioBufferList *ioData, float volume) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static OSStatus renderCallback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData) {
|
static OSStatus renderCallback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData) {
|
||||||
|
@autoreleasepool {
|
||||||
OutputCoreAudio *_self = (__bridge OutputCoreAudio *)inRefCon;
|
OutputCoreAudio *_self = (__bridge OutputCoreAudio *)inRefCon;
|
||||||
|
|
||||||
const int channels = _self->deviceFormat.mChannelsPerFrame;
|
const int channels = _self->deviceFormat.mChannelsPerFrame;
|
||||||
|
@ -150,6 +151,7 @@ static OSStatus renderCallback(void *inRefCon, AudioUnitRenderActionFlags *ioAct
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
- (id)initWithController:(OutputNode *)c {
|
- (id)initWithController:(OutputNode *)c {
|
||||||
|
@ -220,7 +222,9 @@ default_device_changed(AudioObjectID inObjectID, UInt32 inNumberAddresses, const
|
||||||
}
|
}
|
||||||
|
|
||||||
if([outputController shouldReset]) {
|
if([outputController shouldReset]) {
|
||||||
|
@autoreleasepool {
|
||||||
[[outputController buffer] reset];
|
[[outputController buffer] reset];
|
||||||
|
}
|
||||||
[outputController setShouldReset:NO];
|
[outputController setShouldReset:NO];
|
||||||
[delayedEvents removeAllObjects];
|
[delayedEvents removeAllObjects];
|
||||||
delayedEventsPopped = YES;
|
delayedEventsPopped = YES;
|
||||||
|
@ -244,12 +248,14 @@ default_device_changed(AudioObjectID inObjectID, UInt32 inNumberAddresses, const
|
||||||
size_t frameCount = 0;
|
size_t frameCount = 0;
|
||||||
|
|
||||||
if(![[outputController buffer] isFull]) {
|
if(![[outputController buffer] isFull]) {
|
||||||
|
@autoreleasepool {
|
||||||
AudioChunk *chunk = [outputController readChunk:512];
|
AudioChunk *chunk = [outputController readChunk:512];
|
||||||
frameCount = [chunk frameCount];
|
frameCount = [chunk frameCount];
|
||||||
if(frameCount) {
|
if(frameCount) {
|
||||||
[[outputController buffer] addChunk:chunk];
|
[[outputController buffer] addChunk:chunk];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(frameCount) {
|
if(frameCount) {
|
||||||
[readSemaphore signal];
|
[readSemaphore signal];
|
||||||
|
@ -467,7 +473,9 @@ default_device_changed(AudioObjectID inObjectID, UInt32 inNumberAddresses, const
|
||||||
AVAudioFormat *renderFormat;
|
AVAudioFormat *renderFormat;
|
||||||
|
|
||||||
[outputController incrementAmountPlayed:[[outputController buffer] listDuration]];
|
[outputController incrementAmountPlayed:[[outputController buffer] listDuration]];
|
||||||
|
@autoreleasepool {
|
||||||
[[outputController buffer] reset];
|
[[outputController buffer] reset];
|
||||||
|
}
|
||||||
|
|
||||||
_deviceFormat = format;
|
_deviceFormat = format;
|
||||||
deviceFormat = *(format.streamDescription);
|
deviceFormat = *(format.streamDescription);
|
||||||
|
|
Loading…
Reference in a new issue