2013-12-19 126 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