Почему память iOS AudioQueue постоянно увеличивается?

У меня есть аудиокласс Play, используемый AudioToolBox.framework, AudioQueue.

Я столкнулся с проблемой, при каждом воспроизведении аудиоданных память будет увеличиваться, после завершения воспроизведения память не будет уменьшаться. Если в пакетном тесте будут добавлены сотни мегабайт памяти, я хочу знать, по каким причинам память была увеличена, аудиоданные при каждом проходе каждого объекта освобождаются или по другим причинам.

Вот мой код класса playThread:

@interface PlayThread()
{
    BOOL transferDataComplete; // if thers is no data transfer to   playthread set transferDataComplete = yes;
    NSMutableArray *receiveDataArray;// audio data array
    BOOL isPlay;// if audioqueue start,isPlay = yes,
}
@end
#pragma mark class implementation
@implementation PlayThread
- (instancetype)init
{
    if (self = [super init]) {
        receiveDataArray = [[NSMutableArray alloc]init];
        isPlay = NO;
        transferDataComplete = false;
        bufferOverCount = QUEUE_BUFFER_SIZE;
        audioQueue = nil;
    }
    return self;
}

// audio queue callback function
static void BufferCallback(void *inUserData,AudioQueueRef    inAQ,AudioQueueBufferRef buffer)
{
    USCPlayThread* player=(__bridge USCPlayThread*)inUserData;
    [player fillBuffer:inAQ queueBuffer:buffer];
}
// fill buffer
-(void)fillBuffer:(AudioQueueRef)queue queueBuffer:(AudioQueueBufferRef)buffer
{
    while (true){
        NSData *audioData = [self getAudioData];
        if( transferDataComplete && audioData == nil) {
           bufferOverCount --;
           break;
        }
        else if(audioData != nil){
            memcpy(buffer->mAudioData, [audioData bytes] , audioData.length);
                buffer->mAudioDataByteSize = (UInt32)audioData.length;
                AudioQueueEnqueueBuffer(queue, buffer, 0, NULL);
                break;
            }
            else
                break;
        } // while
        if(bufferOverCount == 0){
            // stop audioqueue
            [self stopAudioQueue];
             dispatch_async(dispatch_get_main_queue(), ^{
                if ([self.delegate respondsToSelector:@selector(playComplete)])     {
                    [self.delegate playComplete];
                }
            });
        }
    }

-(void)addPlayData:(NSData *)data
{
    NSUInteger count = 0;
     @synchronized(receiveDataArray){
        [receiveDataArray addObject:data];
    }
 }
 /**
 *  get data from receiveDataArray
 */
-(NSData*)getAudioData
{
    NSData *headData = nil;
    @synchronized(receiveDataArray){
        if(receiveDataArray.count > 0){
            headData = [receiveDataArray objectAtIndex:0];
            [receiveDataArray removeObjectAtIndex:0];
        }
    }
    return headData;
}

- (void)startPlay // start audioqueue to play audio data
{
    [self reset];
    [self open];
    for(int i=0; i<QUEUE_BUFFER_SIZE; i++)
    {
        [self fillBuffer:audioQueue queueBuffer:audioQueueBuffers[i]];
    }
    // audioqueuestart
    AudioQueueStart(audioQueue, NULL);

    @synchronized(self){
        isPlay = YES;
    }
    if ([self.delegate respondsToSelector:@selector(playBegin)]) {
        [self.delegate playBegin];
    }
}
-(void)createAudioQueue
{
    if (audioQueue) {
        return;
    }
    AudioQueueNewOutput(&audioDescription, BufferCallback, (__bridge void *)(self), nil, nil, 0, &audioQueue);
    if(audioQueue){
        for(int i=0;i<QUEUE_BUFFER_SIZE;i++){
            AudioQueueAllocateBufferWithPacketDescriptions(audioQueue, EVERY_READ_LENGTH, 0, &audioQueueBuffers[i]);
        }
    }
}
-(void)stopAudioQueue
{
    if(audioQueue == nil){
        return;
    }
    @synchronized(self){
        if(isPlay){
            isPlay = NO;
        }
    }
    AudioQueueStop(audioQueue, TRUE);
}
-(void)setAudioFormat
{
    audioDescription.mSampleRate = 16000;
    audioDescription.mFormatID = kAudioFormatLinearPCM;
    audioDescription.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
    audioDescription.mChannelsPerFrame = 1;
    audioDescription.mFramesPerPacket = 1;
    audioDescription.mBitsPerChannel = 16;
    audioDescription.mBytesPerFrame = (audioDescription.mBitsPerChannel/8) *      audioDescription.mChannelsPerFrame;
    audioDescription.mBytesPerPacket = audioDescription.mBytesPerFrame ;
  }

  -(void)close
    {
       if (audioQueue) {
        AudioQueueStop(audioQueue, true);
        AudioQueueDispose(audioQueue, true);
        audioQueue = nil;
        isPlay = NO;
    }
}

-(BOOL)open {
    if([self isOpen]){
        return YES;
    }
    [self close];
    [self setAudioFormat];
    [self createAudioQueue];
    return YES;
}

-(BOOL)isOpen
{
    return (audioQueue != nil);
}

- (void)reset
{
    bufferOverCount = QUEUE_BUFFER_SIZE;
    transferDataComplete = NO;
}

- (BOOL)isPlaying
{
    return isPlay;
}

- (void)disposeQueue
{
    if (audioQueue) {
        AudioQueueDispose(audioQueue, YES);
    }
    audioQueue = nil;
}
 - (void)dealloc
{
    [self disposeQueue];
}

Вот ViewContrller.m:

- (void)viewDidLoad {
[super viewDidLoad];

PlayThread *playThread = [[PlayThread alloc]init];
playThread.delegate = self;
self.playThread = playThread;

for (int  i = 0; i < 10; i++)
{   // create empth audio data to simulate
    NSMutableData *data = [[NSMutableData alloc]initWithLength:10000];
    [self.playThread addPlayData:data];
}
    [self.playThread startPlay]; 
}

Вот метод делегата PlayThread:

// When the play completely,then play once again,memory will continue to increase
- (void)playComplete
{
    dispatch_async(dispatch_get_main_queue(), ^{
        for (int  i = 0; i < 10; i++)
        {
            NSMutableData *data = [[NSMutableData alloc]initWithLength:10000];
            [self.playThread addPlayData:data];
        }
        [self.playThread startPlay];
    });
}

Why memory has continued to increase, how can promptly release memory?


person adolph    schedule 26.01.2015    source источник
comment
Лучший способ увидеть это — запустить инструменты на мониторе памяти.   -  person user523234    schedule 26.01.2015
comment
Пара вопросов, и я посмотрю, не смогу ли я изучить это позже, но 1) это использует ARC и 2) делает ли подкласс PlayThread что-то кроме NSObject?   -  person btomw    schedule 26.01.2015
comment
использует ARC, а PlayThread является подклассом NSObject.   -  person adolph    schedule 26.01.2015
comment
Была такая же проблема. Я решил это, передав CFRunLoopGetCurrent() в inCallbackRunLoop в методе AudioQueueNewOutput.   -  person sudayn    schedule 11.07.2021


Ответы (1)


AudioQueueNewOutput(&audioDescription, BufferCallback, (__bridge void *)(self), nil, nil, 0, &audioQueue); здесь параметр не может быть нулевым

person yixiaojichunqiu    schedule 23.08.2016