2017-01-13 49 views
0
import Foundation 
import AudioToolbox 

class AudioPlay { 

    //setting buffer num 
    static let knumberBuffers = 3 
    var aqData = AQPlayerState.init() 
    //A custom structure for a playback audio queue 
    class AQPlayerState { 
     var mDataFormat = AudioStreamBasicDescription() 
     var mQueue:AudioQueueRef? 
     var mBuffers = [AudioQueueBufferRef?].init(repeating: nil, count: AudioPlay.knumberBuffers) 
     var mAudioFile:AudioFileID? 
     var bufferByteSize = UInt32() 
     var mCurrentPacket:Int64? 
     var mNumPacketsToRead = UInt32() 
     var mPacketDescs:UnsafeMutablePointer<AudioStreamPacketDescription>? 
     var mIsRunning = false 
    }   

    //playbackAudioQueue callback 
    static let HandleOutputBuffer:AudioQueueOutputCallback = { (aqData1, inAQ, inBuffer) in 

     var pAqData = (aqData1?.assumingMemoryBound(to: AQPlayerState.self).pointee)! 

     guard pAqData.mIsRunning || pAqData.mQueue != nil else{ 
      print("audioplay is not running exit callback func") 
      return 
     } 
     var numBytesReadFromFile = UInt32() 
     var numPackets = pAqData.mNumPacketsToRead 

     AudioFileReadPacketData(pAqData.mAudioFile!, false, &numBytesReadFromFile, pAqData.mPacketDescs, pAqData.mCurrentPacket!, &numPackets, inBuffer.pointee.mAudioData) 

     if numPackets > 0 { 
      inBuffer.pointee.mAudioDataByteSize = numBytesReadFromFile 

      AudioQueueEnqueueBuffer(pAqData.mQueue!, inBuffer, ((pAqData.mPacketDescs != nil) ? numPackets : UInt32(0)), pAqData.mPacketDescs) 

      pAqData.mCurrentPacket! += Int64(numPackets) 
     }else{ 
      AudioQueueStop(pAqData.mQueue!, false) 
      pAqData.mIsRunning = false 
     }  
    }  

    //call func to set the property 
    //create new outputqueue 
    //start th audioqueue 
    func start() { 

     let url = Bundle.main.url(forResource: "123", withExtension: "mp3")! 

     let audioFileURL = url as CFURL  

     print(audioFileURL)   

     let result = AudioFileOpenURL(audioFileURL, .readPermission, 0, &aqData.mAudioFile) 
     print(result)  

     var dataFormatSize = UInt32(MemoryLayout.size(ofValue: aqData.mDataFormat)) 

     let result1 = AudioFileGetProperty(aqData.mAudioFile!, kAudioFilePropertyDataFormat,&dataFormatSize, &aqData.mDataFormat)  

     //get file property 
     var maxPacketSize = UInt32()    
     var propertySize = UInt32(MemoryLayout.size(ofValue: maxPacketSize))    

     let result2 = AudioFileGetProperty(aqData.mAudioFile!, kAudioFilePropertyPacketSizeUpperBound, &propertySize, &maxPacketSize)   

     //calculate and setting buffer size 
     DeriveBufferSize(ASBDesc: aqData.mDataFormat, maxPacketSize: maxPacketSize, seconds: 0.5, outBufferSize: &aqData.bufferByteSize, outNumPacketsToRead: &aqData.mNumPacketsToRead) 

     //check the format is VBR or CBR 
     let isFormatVBR = aqData.mDataFormat.mBytesPerPacket == 0 || aqData.mDataFormat.mFramesPerPacket == 0 

     if isFormatVBR { 
      aqData.mPacketDescs = UnsafeMutablePointer<AudioStreamPacketDescription>.allocate(capacity: MemoryLayout.size(ofValue: AudioStreamPacketDescription())) 
     }else{ 
      aqData.mPacketDescs = nil 
     } 

     //create new audio queue 
     let result4 = AudioQueueNewOutput(&aqData.mDataFormat,AudioPlay.HandleOutputBuffer, &aqData,CFRunLoopGetCurrent(),CFRunLoopMode.commonModes.rawValue, 0, &aqData.mQueue)  

     //queue start 
     aqData.mIsRunning = true 

     //alloc memory buffer 
     aqData.mCurrentPacket = 0 

     for i in 0..<AudioPlay.knumberBuffers { 
      AudioQueueAllocateBuffer(aqData.mQueue!, aqData.bufferByteSize,&aqData.mBuffers[i]) 
      AudioPlay.HandleOutputBuffer(&aqData,aqData.mQueue!, (aqData.mBuffers[i])!) 
     } 

     //start audioqueue 
     AudioQueueStart(aqData.mQueue!, nil)    

     repeat{ 
      CFRunLoopRunInMode(CFRunLoopMode.defaultMode, 0.25, false) 
     }while (aqData.mIsRunning) 

     CFRunLoopRunInMode(CFRunLoopMode.defaultMode, 1, false)   
    }  

    //calculate and setting buffer size 
    func DeriveBufferSize(ASBDesc:AudioStreamBasicDescription,maxPacketSize:UInt32,seconds:Float64,outBufferSize:UnsafeMutablePointer<UInt32>,outNumPacketsToRead:UnsafeMutablePointer<UInt32>) { 
     let maxBufferSize:UInt32 = 0x50000 
     let minBufferSIze:UInt32 = 0x4000 

     if ASBDesc.mFramesPerPacket != 0 { 
      let numPacketsForTime = ASBDesc.mSampleRate/Float64(ASBDesc.mFramesPerPacket) * seconds 
      outBufferSize.pointee = UInt32(numPacketsForTime) * maxPacketSize 
     }else{ 
      outBufferSize.pointee = (maxBufferSize > maxPacketSize) ? maxBufferSize:maxPacketSize 
     } 

     if outBufferSize.pointee > maxBufferSize && outBufferSize.pointee > maxPacketSize { 
      outBufferSize.pointee = maxBufferSize 
     }else{ 
      if outBufferSize.pointee < minBufferSIze{ 
       outBufferSize.pointee = minBufferSIze 
      } 
     } 
     outNumPacketsToRead.pointee = outBufferSize.pointee/maxPacketSize 
    }  

    //dispose the audioqueue 
    func Dispose() { 
     AudioQueueDispose(aqData.mQueue!, true) 
     AudioFileClose(aqData.mAudioFile!) 
     free(aqData.mPacketDescs) 
    }   
} 

上面的代码是根据AudioQueueServiceProgrammingGuide编写的!AudioQueueStart但没有声音

创建此类的句子,并调用start()func 编译ok,但没有输出语音。 我已经检查了很多次,但没有前进

任何熟悉audiiqueue的人都能帮助我吗? 任何帮助将不胜感激。

回答

0

将“AudioFileReadPacketData”替换为“AudioFileReadPackets”可以解决此问题!

但我得到一个新的问题,像下面的某个时候!有时它运作良好!

流音频(20535,0x1085ac3c0)的malloc:*错误对象0x6080001f6300:无效的指针从空闲列表离队 *设置malloc_error_break断点