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>
CQTexperiment
Christopher Snowhill 2022-02-07 04:06:36 -08:00
parent 6120fce40a
commit acb1dd75d3
4 changed files with 117 additions and 96 deletions

View File

@ -49,7 +49,7 @@
}
- (BOOL)isFull {
return listDuration >= maxDuration;
return (maxDuration - listDuration) < 0.01;
}
- (void)addChunk:(AudioChunk *)chunk {

View File

@ -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,
// and returns 0 samples when it has nothing more to process at the end of stream.
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(paused) {
while(paused)
@ -985,6 +988,7 @@ static float db_to_scale(float db) {
[refillNode setChannelConfig:previousOutputConfig];
for(;;) {
@autoreleasepool {
AudioChunk *chunk = [buffer removeSamples:16384];
size_t frameCount = [chunk frameCount];
if(frameCount) {
@ -993,6 +997,7 @@ static float db_to_scale(float db) {
} else
break;
}
}
[self setupWithInputFormat:previousOutputFormat withInputConfig:[AudioChunk guessChannelConfig:previousOutputFormat.mChannelsPerFrame] outputFormat:outputFormat outputConfig:outputChannelConfig isLossless:rememberedLossless];
} else {

View File

@ -105,7 +105,9 @@
}
if([previousNode shouldReset] == YES) {
@autoreleasepool {
[buffer reset];
}
shouldReset = YES;
[previousNode setShouldReset:NO];
@ -113,7 +115,11 @@
[[previousNode semaphore] signal];
}
AudioChunk *ret = [[previousNode buffer] removeSamples:maxFrames];
AudioChunk *ret;
@autoreleasepool {
ret = [[previousNode buffer] removeSamples:maxFrames];
}
[accessLock unlock];
@ -151,11 +157,13 @@
- (void)resetBuffer {
shouldReset = YES; // Will reset on next write.
if(previousNode == nil) {
@autoreleasepool {
[accessLock lock];
[buffer reset];
[accessLock unlock];
}
}
}
- (Semaphore *)semaphore {
return semaphore;

View File

@ -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) {
@autoreleasepool {
OutputCoreAudio *_self = (__bridge OutputCoreAudio *)inRefCon;
const int channels = _self->deviceFormat.mChannelsPerFrame;
@ -150,6 +151,7 @@ static OSStatus renderCallback(void *inRefCon, AudioUnitRenderActionFlags *ioAct
}
return 0;
}
};
- (id)initWithController:(OutputNode *)c {
@ -220,7 +222,9 @@ default_device_changed(AudioObjectID inObjectID, UInt32 inNumberAddresses, const
}
if([outputController shouldReset]) {
@autoreleasepool {
[[outputController buffer] reset];
}
[outputController setShouldReset:NO];
[delayedEvents removeAllObjects];
delayedEventsPopped = YES;
@ -244,12 +248,14 @@ default_device_changed(AudioObjectID inObjectID, UInt32 inNumberAddresses, const
size_t frameCount = 0;
if(![[outputController buffer] isFull]) {
@autoreleasepool {
AudioChunk *chunk = [outputController readChunk:512];
frameCount = [chunk frameCount];
if(frameCount) {
[[outputController buffer] addChunk:chunk];
}
}
}
if(frameCount) {
[readSemaphore signal];
@ -467,7 +473,9 @@ default_device_changed(AudioObjectID inObjectID, UInt32 inNumberAddresses, const
AVAudioFormat *renderFormat;
[outputController incrementAmountPlayed:[[outputController buffer] listDuration]];
@autoreleasepool {
[[outputController buffer] reset];
}
_deviceFormat = format;
deviceFormat = *(format.streamDescription);