2013-12-19 96 views
2

所以,基本上我想播放一些audio files(主要是mp3和caf)。但回調永遠不會被調用。只有當我打電話給他們排隊時。Audioqueue回調不被稱爲

這裏是我的數據結構:

struct AQPlayerState 
{ 
    CAStreamBasicDescription  mDataFormat; 
    AudioQueueRef     mQueue; 
    AudioQueueBufferRef    mBuffers[kBufferNum]; 
    AudioFileID      mAudioFile; 
    UInt32       bufferByteSize; 
    SInt64       mCurrentPacket; 
    UInt32       mNumPacketsToRead; 
    AudioStreamPacketDescription *mPacketDescs; 
    bool       mIsRunning; 
}; 

這是我的回調函數:

static void HandleOutputBuffer (void *aqData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer) 
{ 
    NSLog(@"HandleOutput"); 
    AQPlayerState *pAqData = (AQPlayerState *) aqData; 

    if (pAqData->mIsRunning == false) return; 

    UInt32 numBytesReadFromFile; 
    UInt32 numPackets = pAqData->mNumPacketsToRead; 
    AudioFileReadPackets (pAqData->mAudioFile, 
          false, 
          &numBytesReadFromFile, 
          pAqData->mPacketDescs, 
          pAqData->mCurrentPacket, 
          &numPackets, 
          inBuffer->mAudioData); 
    if (numPackets > 0) {  
     inBuffer->mAudioDataByteSize = numBytesReadFromFile; 
     AudioQueueEnqueueBuffer (pAqData->mQueue, 
           inBuffer, 
           (pAqData->mPacketDescs ? numPackets : 0), 
           pAqData->mPacketDescs); 
     pAqData->mCurrentPacket += numPackets; 
    } else { 
//  AudioQueueStop(pAqData->mQueue, false); 
//  AudioQueueDispose(pAqData->mQueue, true); 
//  AudioFileClose (pAqData->mAudioFile); 
//  free(pAqData->mPacketDescs); 
//  free(pAqData->mFloatBuffer); 
     pAqData->mIsRunning = false; 
    } 
} 

這是我的方法:

- (void)playFile 
{ 
    AQPlayerState aqData; 

    // get the source file 
    NSString *p = [[NSBundle mainBundle] pathForResource:@"1_Female" ofType:@"mp3"]; 
    NSURL *url2 = [NSURL fileURLWithPath:p]; 
    CFURLRef srcFile = (__bridge CFURLRef)url2; 

    OSStatus result = AudioFileOpenURL(srcFile, 0x1/*fsRdPerm*/, 0/*inFileTypeHint*/, &aqData.mAudioFile); 
    CFRelease (srcFile); 

    CheckError(result, "Error opinning sound file"); 

    UInt32 size = sizeof(aqData.mDataFormat); 
    CheckError(AudioFileGetProperty(aqData.mAudioFile, kAudioFilePropertyDataFormat, &size, &aqData.mDataFormat), 
       "Error getting file's data format"); 

    CheckError(AudioQueueNewOutput(&aqData.mDataFormat, HandleOutputBuffer, &aqData, CFRunLoopGetCurrent(), kCFRunLoopCommonModes, 0, &aqData.mQueue), 
       "Error AudioQueueNewOutPut"); 

    // we need to calculate how many packets we read at a time and how big a buffer we need 
    // we base this on the size of the packets in the file and an approximate duration for each buffer 
    { 
     bool isFormatVBR = (aqData.mDataFormat.mBytesPerPacket == 0 || aqData.mDataFormat.mFramesPerPacket == 0); 

     // first check to see what the max size of a packet is - if it is bigger 
     // than our allocation default size, that needs to become larger 
     UInt32 maxPacketSize; 
     size = sizeof(maxPacketSize); 
     CheckError(AudioFileGetProperty(aqData.mAudioFile, kAudioFilePropertyPacketSizeUpperBound, &size, &maxPacketSize), 
        "Error getting max packet size"); 

     // adjust buffer size to represent about a second of audio based on this format 
     CalculateBytesForTime(aqData.mDataFormat, maxPacketSize, 1.0/*seconds*/, &aqData.bufferByteSize, &aqData.mNumPacketsToRead); 

     if (isFormatVBR) { 
      aqData.mPacketDescs = new AudioStreamPacketDescription [aqData.mNumPacketsToRead]; 
     } else { 
      aqData.mPacketDescs = NULL; // we don't provide packet descriptions for constant bit rate formats (like linear PCM) 
     } 

     printf ("Buffer Byte Size: %d, Num Packets to Read: %d\n", (int)aqData.bufferByteSize, (int)aqData.mNumPacketsToRead); 
    } 

    // if the file has a magic cookie, we should get it and set it on the AQ 
    size = sizeof(UInt32); 
    result = AudioFileGetPropertyInfo(aqData.mAudioFile, kAudioFilePropertyMagicCookieData, &size, NULL); 

    if (!result && size) { 
     char* cookie = new char [size]; 
     CheckError(AudioFileGetProperty(aqData.mAudioFile, kAudioFilePropertyMagicCookieData, &size, cookie), 
        "Error getting cookie from file"); 
     CheckError(AudioQueueSetProperty(aqData.mQueue, kAudioQueueProperty_MagicCookie, cookie, size), 
        "Error setting cookie to file"); 
     delete[] cookie; 
    } 

    aqData.mCurrentPacket = 0; 
    for (int i = 0; i < kBufferNum; ++i) { 
     CheckError(AudioQueueAllocateBuffer (aqData.mQueue, 
              aqData.bufferByteSize, 
              &aqData.mBuffers[i]), 
        "Error AudioQueueAllocateBuffer"); 

     HandleOutputBuffer (&aqData, 
          aqData.mQueue, 
          aqData.mBuffers[i]); 
    } 

    // set queue's gain 

    Float32 gain = 1.0; 
    CheckError(AudioQueueSetParameter (aqData.mQueue, 
             kAudioQueueParam_Volume, 
             gain), 
       "Error AudioQueueSetParameter"); 

    aqData.mIsRunning = true; 
    CheckError(AudioQueueStart(aqData.mQueue, 
           NULL), 
       "Error AudioQueueStart"); 

} 

和輸出,當我按下播放鍵:

Buffer Byte Size: 40310, Num Packets to Read: 38 
HandleOutput start 
HandleOutput start 
HandleOutput start 

我嘗試用CFRunLoopGetMain()CFRunLoopCommonModesCFRunLoopDefaultMode替代CFRunLoopGetCurrent(),但沒有任何結果。

不應該啓動緩衝區立即開始播放我開始隊列? 當我啓動隊列時,沒有回調被觸發。 我在做什麼錯?感謝您的任何想法

回答

3

你基本上想要做什麼是一個使用音頻隊列進行音頻播放的基本示例。如果沒有詳細查看代碼以查看缺少的內容(可能需要一段時間),我寧願推薦您遵循this basic sample code中的步驟,這些步驟完全符合您的要求(沒有其他相關的附加內容。 。例如,你爲什麼要添加音頻增益?)

你試圖用音頻單元播放音頻的其他地方。音頻單元比基本的音頻隊列播放更爲複雜,在對音頻隊列非常舒適之前,我不會嘗試它們。但你可以看看這個example project的音頻隊列的基本例子。

一般來說,當涉及到iOS的Core Audio編程時,最好你花時間處理基本的例子並建立自己的方式。網上有很多教程的問題是它們添加額外的東西,並經常混合它與obj-c代碼..當核心音頻純粹是C代碼(即額外的東西不會添加任何東西到學習過程中)。如果你還沒有,我強烈建議你閱讀Learning Core Audio。所有示例代碼都可以在線獲得,但爲了方便起見,您還可以從this回購克隆它。這就是我學習核心音頻的方式。它需要時間:)

+0

謝謝abbood,我會通過示例代碼;) – Skiny

+0

終於得到它的工作! Jeeeeez:D文件播放器的例子有一些我錯過了 – Skiny

+0

@Skiny嘿男人很高興它解決了。核心音頻是一個不同的動物,當涉及到iOS ..它需要大量的培訓和閱讀..再次,我強烈建議您閱讀本書..並使用示例..他們是救生員 – abbood