2015-01-08 2 views
2

У меня есть следующий код, который открывает AudioQueue для воспроизведения 16 бит pcm @ 44,100hz. У этого есть очень странная причуда, где, когда начальные буферы заполнены, он воспроизводит очень быстро, затем становится «прерывистым», так как он ждет больше байтов, которые попадают по сети.Превосходное воспроизведение звука с помощью 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) Я правильно не задал buffer-> mAudioDataByteSize в обратном вызове и 2) я использовал слишком мало буферов; увеличение буферов от 3 до 5 решило мою последнюю оставшуюся проблему затухания звука. –

ответ

0

Я собираюсь взять хабар здесь и сказать, что вы получаете прерывистое воспроизведение, потому что вы не опережение указателя записи ваших данных. Я не знаю, Objective-C достаточно хорошо, чтобы сказать вам, если этот синтаксис является правильным, но вот что я думаю, что вам нужно добавить:

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

 Смежные вопросы

  • Нет связанных вопросов^_^