2017-05-25 8 views
2

私はAudio Queue Servicesで約1週間プレイしてきましたが、Apple Audio Queue Services Guideから速いバージョンを書いています。 私はリニアPCMで記録し、この方法でディスクに保存しています:Audio Queue Services Swiftのプレイヤーがコールバックを呼び出さない

AudioFileCreateWithURL(url, kAudioFileWAVEType, &format, 
              AudioFileFlags.dontPageAlignAudioData.union(.eraseFile), &audioFileID) 
私AudioQueueOutputCallbackは私がbufferSizeが十分一見大きく、それが実際のデータを渡さなってきていることことを確認することができていても呼び出されていません。私はOSStatusのエラーを取得していないとすべてがうまくいくように思える。 SwiftがAudioServiceQueuesを書いたのはごくわずかです。私はこのコードを残しておきたいと思います。

すべてのご提案をお待ちしております。

class SVNPlayer: SVNPlayback { 

    var state: PlayerState! 

    private let callback: AudioQueueOutputCallback = { aqData, inAQ, inBuffer in 

    guard let userData = aqData else { return } 
    let audioPlayer = Unmanaged<SVNPlayer>.fromOpaque(userData).takeUnretainedValue() 

    guard audioPlayer.state.isRunning, 
     let queue = audioPlayer.state.mQueue else { return } 

    var buffer = inBuffer.pointee // dereference pointers 

    var numBytesReadFromFile: UInt32 = 0 
    var numPackets = audioPlayer.state.mNumPacketsToRead 
    var mPacketDescIsNil = audioPlayer.state.mPacketDesc == nil // determine if the packetDesc 

    if mPacketDescIsNil { 
     audioPlayer.state.mPacketDesc = AudioStreamPacketDescription(mStartOffset: 0, mVariableFramesInPacket: 0, mDataByteSize: 0) 
    } 

    AudioFileReadPacketData(audioPlayer.state.mAudioFile, false, &numBytesReadFromFile, // read the packet at the saved file 
     &audioPlayer.state.mPacketDesc!, audioPlayer.state.mCurrentPacket, 
     &numPackets, buffer.mAudioData) 

    if numPackets > 0 { 
     buffer.mAudioDataByteSize = numBytesReadFromFile 
     AudioQueueEnqueueBuffer(queue, inBuffer, mPacketDescIsNil ? numPackets : 0, 
           &audioPlayer.state.mPacketDesc!) 
     audioPlayer.state.mCurrentPacket += Int64(numPackets) 
    } else { 
     AudioQueueStop(queue, false) 
     audioPlayer.state.isRunning = false 
    } 
    } 

    init(inputPath: String, audioFormat: AudioStreamBasicDescription, numberOfBuffers: Int) throws { 
    super.init() 
    var format = audioFormat 
    let pointer = UnsafeMutableRawPointer(Unmanaged.passUnretained(self).toOpaque()) // get an unmananged reference to self 

    guard let audioFileUrl = CFURLCreateFromFileSystemRepresentation(nil, 
                    inputPath, 
                    CFIndex(strlen(inputPath)), false) else { 
                     throw MixerError.playerInputPath } 

    var audioFileID: AudioFileID? 

    try osStatus { AudioFileOpenURL(audioFileUrl, AudioFilePermissions.readPermission, 0, &audioFileID) } 

    guard audioFileID != nil else { throw MixerError.playerInputPath } 

    state = PlayerState(mDataFormat: audioFormat, // setup the player state with mostly initial values 
     mQueue: nil, 
     mAudioFile: audioFileID!, 
     bufferByteSize: 0, 
     mCurrentPacket: 0, 
     mNumPacketsToRead: 0, 
     isRunning: false, 
     mPacketDesc: nil, 
     onError: nil) 

    var dataFormatSize = UInt32(MemoryLayout<AudioStreamBasicDescription>.stride) 

    try osStatus { AudioFileGetProperty(audioFileID!, kAudioFilePropertyDataFormat, &dataFormatSize, &state.mDataFormat) } 

    var queue: AudioQueueRef? 

    try osStatus { AudioQueueNewOutput(&format, callback, pointer, CFRunLoopGetCurrent(), CFRunLoopMode.commonModes.rawValue, 0, &queue) } // setup output queue 

    guard queue != nil else { throw MixerError.playerOutputQueue } 

    state.mQueue = queue // add to playerState 

    var maxPacketSize = UInt32() 
    var propertySize = UInt32(MemoryLayout<UInt32>.stride) 

    try osStatus { AudioFileGetProperty(state.mAudioFile, kAudioFilePropertyPacketSizeUpperBound, &propertySize, &maxPacketSize) } 

    deriveBufferSize(maxPacketSize: maxPacketSize, seconds: 0.5, outBufferSize: &state.bufferByteSize, outNumPacketsToRead: &state.mNumPacketsToRead) 

    let isFormatVBR = state.mDataFormat.mBytesPerPacket == 0 || state.mDataFormat.mFramesPerPacket == 0 

    if isFormatVBR { //Allocating Memory for a Packet Descriptions Array 
     let size = UInt32(MemoryLayout<AudioStreamPacketDescription>.stride) 
     state.mPacketDesc = AudioStreamPacketDescription(mStartOffset: 0, 
                 mVariableFramesInPacket: state.mNumPacketsToRead, 
                 mDataByteSize: size) 


    } // if CBR it stays set to null 

    for _ in 0..<numberOfBuffers { // Allocate and Prime Audio Queue Buffers 
     let bufferRef = UnsafeMutablePointer<AudioQueueBufferRef?>.allocate(capacity: 1) 
     let foo = state.mDataFormat.mBytesPerPacket * 1024/UInt32(numberOfBuffers) 
     try osStatus { AudioQueueAllocateBuffer(state.mQueue!, foo, bufferRef) } // allocate the buffer 

     if let buffer = bufferRef.pointee { 
     AudioQueueEnqueueBuffer(state.mQueue!, buffer, 0, nil) 
     } 
    } 

    let gain: Float32 = 1.0 // Set an Audio Queue’s Playback Gain 
    try osStatus { AudioQueueSetParameter(state.mQueue!, kAudioQueueParam_Volume, gain) } 
    } 

    func start() throws { 
    state.isRunning = true // Start and Run an Audio Queue 
    try osStatus { AudioQueueStart(state.mQueue!, nil) } 
    while state.isRunning { 
     CFRunLoopRunInMode(CFRunLoopMode.defaultMode, 0.25, false) 
    } 
    CFRunLoopRunInMode(CFRunLoopMode.defaultMode, 1.0, false) 
    state.isRunning = false 
    } 

    func stop() throws { 
    guard state.isRunning, 
     let queue = state.mQueue else { return } 
    try osStatus { AudioQueueStop(queue, true) } 
    try osStatus { AudioQueueDispose(queue, true) } 
    try osStatus { AudioFileClose(state.mAudioFile) } 

    state.isRunning = false 
    } 


    private func deriveBufferSize(maxPacketSize: UInt32, seconds: Float64, outBufferSize: inout UInt32, outNumPacketsToRead: inout UInt32){ 
    let maxBufferSize = UInt32(0x50000) 
    let minBufferSize = UInt32(0x4000) 

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

    if outBufferSize > maxBufferSize && outBufferSize > maxPacketSize { 
     outBufferSize = maxBufferSize 

    } else if outBufferSize < minBufferSize { 
     outBufferSize = minBufferSize 
    } 

    outNumPacketsToRead = outBufferSize/maxPacketSize 
    } 
} 

マイ選手状態構造体は次のようになります。代わりに、空のバッファをエンキューの

struct PlayerState: PlaybackState { 
    var mDataFormat: AudioStreamBasicDescription 
    var mQueue: AudioQueueRef? 
    var mAudioFile: AudioFileID 
    var bufferByteSize: UInt32 
    var mCurrentPacket: Int64 
    var mNumPacketsToRead: UInt32 
    var isRunning: Bool 
    var mPacketDesc: AudioStreamPacketDescription? 
    var onError: ((Error) -> Void)? 
} 

答えて

1

、それは(たぶん)フルバッファをキューに登録し、あなたのcallbackを呼び出してみてください。私はランロップのものについては確信していますが、私はあなたが何をしているのか知っていると確信しています。

+0

私は理解できません。 'EnqueueBuffer'を呼び出す代わりにコールバックを呼び出す必要がある各バッファを割り当てた後であることを意味しますか?それは、それが私が持っているバッファの数だけ呼ばれることを意味しないでしょうか?私はそれを行ったが、AudioQueueStartでは何もしないようだ。その他の提案はありますか?ありがとう! – aBikis

+1

これは正しいことですが、コールバックは 'EnqueueBuffer'を呼び出しますが、それが役に立たない場合は、動作するコードサンプルへのリンクを投稿できますか? –

+0

本当にうわー?それは信じられないでしょう。私は実際に少しソースコードを更新しました。私はこの素早いファイルを嘲笑しているCコードを使ってオーディオを再生することができました。私はそれを正しくエンキューしていると思いますが、パケットデータから問題を読み取っているようです。私はすべての関連ファイルを含んでおり、問題のある行は 'SVNPlayer'行30にあります。ありがとうございました! https://gist.github.com/bikisDesign/57c58355c2cb4498595dab52f0ff0be8 – aBikis

関連する問題