2017-05-25 3 views
2

Ich habe ungefähr eine Woche mit Audio Queue Services herumgespielt und ich habe eine schnelle Version von Apple Audio Queue Services Guide geschrieben. ich im Linear PCM-Aufnahme und mit dieser Methode auf der Festplatte zu speichern:Audio Queue Services Player in Swift ruft keinen Rückruf an

AudioFileCreateWithURL(url, kAudioFileWAVEType, &format, 
              AudioFileFlags.dontPageAlignAudioData.union(.eraseFile), &audioFileID) 

Mein AudioQueueOutputCallback nicht einmal genannt wird, obwohl ich überprüfen kann, dass meine buffer scheinbar groß genug ist, und dass es tatsächlich Daten übergeben zu werden. Ich erhalte keine OSStatus-Fehler und es scheint, als ob alles funktionieren sollte. Theres sehr wenig in der Art von Swift geschriebenen AudioServiceQueues und sollte ich das funktionieren, würde ich mich freuen, den Rest meines Codes zu öffnen.

Alle und alle Vorschläge willkommen!

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 
    } 
} 

Mein Player Zustand Struktur ist:

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)? 
} 

Antwort

1

Statt einen leeren Puffer von Einreihen, versuchen Sie fordern callback so es reiht einen (hoffentlich) vollständige Puffer. Ich bin unsicher über die Runloop-Sachen, aber ich bin sicher, du weißt, was du tust.

+0

Hmm Ich bin mir nicht sicher, ob ich das verstehe. Meinst du, nach dem Zuweisen jedes Puffers sollte ich den Callback aufrufen anstatt "EnqueueBuffer" aufzurufen? Würde das nicht bedeuten, dass es nur für die Anzahl der Puffer, die ich habe, erforderlich wäre? Ich habe es versucht und es scheint nichts auf AudioQueueStart zu tun. Irgendwelche anderen Vorschläge? Vielen Dank! – aBikis

+1

Das ist richtig, der Callback ruft "EnqueueBuffer" auf, aber wenn das nicht hilft, können Sie einen Link zu einem funktionierenden Codebeispiel posten? –

+0

Wow wirklich? Das wäre unglaublich. Ich habe den Quellcode tatsächlich ein wenig aktualisiert. Ich war in der Lage, Audio über den C-Code abzuspielen, über den ich diese schnelle Datei verspottet habe, und ich denke, ich habe es korrekt in die Warteschlange gestellt, aber es scheint ein Problem beim Lesen der Paketdaten zu geben. Ich habe alle relevanten Dateien eingeschlossen und die problematische Zeile ist in "SVNPlayer" Zeile 30. Vielen Dank! https://gist.github.com/bikisDesign/57c58355c2cb4498595dab52f0ff0be8 – aBikis

Verwandte Themen