2015-01-08 4 views
2

다음 코드는 AudioQueue를 열어 16 비트 pcm @ 44,100hz를 재생합니다. 초기 버퍼가 채워지면 정말 빨리 재생 된 다음 네트워크를 통해 더 많은 바이트를 기다리는 동안 "고르지 (choppy)"가됩니다.AudioQueue로 고르지 않은 오디오 재생

그래서 데이터의 부분 범위를 버퍼에 복사하는 코드를 망가 뜨리거나 네트워크를 통해 데이터를 재생하는 것보다 AudioQueue가 더 빨리 재생하도록 말했습니다.

아무도 아이디어가 있습니까? 나는 며칠 동안 붙어 있었어.

// 
// Created by Benjamin St Pierre on 15-01-02. 
// Copyright (c) 2015 Lightning Strike Solutions. All rights reserved. 
// 

#import <MacTypes.h> 
#import "MediaPlayer.h" 


@implementation MediaPlayer 


@synthesize sampleQueue; 


void OutputBufferCallback(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer) { 
    //Cast userData to MediaPlayer Objective-C class instance 
    MediaPlayer *mediaPlayer = (__bridge MediaPlayer *) inUserData; 
    // Fill buffer. 
    [mediaPlayer fillAudioBuffer:inBuffer]; 
    // Re-enqueue buffer. 
    OSStatus err = AudioQueueEnqueueBuffer(inAQ, inBuffer, 0, NULL); 
    if (err != noErr) 
     NSLog(@"AudioQueueEnqueueBuffer() error %d", (int) err); 
} 

- (void)fillAudioBuffer:(AudioQueueBufferRef)inBuffer { 
    if (self.currentAudioPiece == nil || self.currentAudioPiece.duration >= self.currentAudioPieceIndex) { 
     //grab latest sample from sample queue 
     self.currentAudioPiece = sampleQueue.dequeue; 
     self.currentAudioPieceIndex = 0; 
    } 

    //Check for empty sample queue 
    if (self.currentAudioPiece == nil) { 
     NSLog(@"Empty sample queue"); 
     memset(inBuffer->mAudioData, 0, kBufferByteSize); 
     return; 
    } 

    UInt32 bytesToRead = inBuffer->mAudioDataBytesCapacity; 

    while (bytesToRead > 0) { 
     UInt32 maxBytesFromCurrentPiece = self.currentAudioPiece.audioData.length - self.currentAudioPieceIndex; 
     //Take the min of what the current piece can provide OR what is needed to be read 
     UInt32 bytesToReadNow = MIN(maxBytesFromCurrentPiece, bytesToRead); 

     NSData *subRange = [self.currentAudioPiece.audioData subdataWithRange:NSMakeRange(self.currentAudioPieceIndex, bytesToReadNow)]; 
     //Copy what you can before continuing loop 
     memcpy(inBuffer->mAudioData, subRange.bytes, subRange.length); 
     bytesToRead -= bytesToReadNow; 

     if (bytesToReadNow == maxBytesFromCurrentPiece) { 
      @synchronized (sampleQueue) { 
       self.currentAudioPiece = self.sampleQueue.dequeue; 
       self.currentAudioPieceIndex = 0; 
      } 
     } else { 
      self.currentAudioPieceIndex += bytesToReadNow; 
     } 
    } 
    inBuffer->mAudioDataByteSize = kBufferByteSize; 
} 

- (void)startMediaPlayer { 
    AudioStreamBasicDescription streamFormat; 
    streamFormat.mFormatID = kAudioFormatLinearPCM; 
    streamFormat.mSampleRate = 44100.0; 
    streamFormat.mChannelsPerFrame = 2; 
    streamFormat.mBytesPerFrame = 4; 
    streamFormat.mFramesPerPacket = 1; 
    streamFormat.mBytesPerPacket = 4; 
    streamFormat.mBitsPerChannel = 16; 
    streamFormat.mReserved = 0; 
    streamFormat.mFormatFlags = kAudioFormatFlagIsPacked | kAudioFormatFlagIsSignedInteger; 

    // New input queue 
    OSStatus err = AudioQueueNewOutput(&streamFormat, OutputBufferCallback, (__bridge void *) self, nil, nil, 0, &outputQueue); 
    if (err != noErr) { 
     NSLog(@"AudioQueueNewOutput() error: %d", (int) err); 
    } 

    int i; 
    // Enqueue buffers 
    AudioQueueBufferRef buffer; 
    for (i = 0; i < kNumberBuffers; i++) { 
     err = AudioQueueAllocateBuffer(outputQueue, kBufferByteSize, &buffer); 
     memset(buffer->mAudioData, 0, kBufferByteSize); 
     buffer->mAudioDataByteSize = kBufferByteSize; 
     if (err == noErr) { 
      err = AudioQueueEnqueueBuffer(outputQueue, buffer, 0, nil); 
      if (err != noErr) NSLog(@"AudioQueueEnqueueBuffer() error: %d", (int) err); 
     } else { 
      NSLog(@"AudioQueueAllocateBuffer() error: %d", (int) err); 
      return; 
     } 
    } 

    // Start queue 
    err = AudioQueueStart(outputQueue, nil); 
    if (err != noErr) NSLog(@"AudioQueueStart() error: %d", (int) err); 
} 

@end 
+0

당신이 렌더링 콜백에서 Objective-C 코드를 호출하고있다. 이는 일반적으로 실시간으로 안전하며 과부하로 이어질 수 있습니다. '-fillAudioBuffer :'에서 뮤텍스는 확실히 실시간으로 안전하지 않습니다. – sbooth

+0

오디오 대기열에서의 첫 번째 시도에서, 나는 두 가지 이유로 사운드 결함이있었습니다. 1) 버퍼 -> mAudioDataByteSize를 콜백에 올바르게 설정하지 않고 2) 버퍼를 너무 적게 사용하고있었습니다. 버퍼를 3에서 5로 늘리면 마지막 남은 오디오 끊김 문제가 해결되었습니다. –

답변

0

여기서 데이터를 가져 오지 않으므로 고르지 않은 재생이 발생한다고 말씀 드리겠습니다. 나는이 문법이 정확한지 당신에게 말할만큼 충분히 잘 모르겠다. 그러나 다음과 같이 추가해야한다고 생각한다 :

while (bytesToRead > 0) { 
    .... 
    memcpy(inBuffer->mAudioData, subRange.bytes, subRange.length); 
    bytesToRead -= bytesToReadNow; 
    inBuffer->mAudioData += bytesReadNow; // move the write pointer 
    ... 
}