代码之家  ›  专栏  ›  技术社区  ›  Ash

Swift中AudioQueue的问题:重复使用缓冲区似乎不起作用

  •  0
  • Ash  · 技术社区  · 7 年前

    我目前看到的问题是,当我将初始缓冲区排队时,在播放这些缓冲区时,会有一点“点击”。然而,当缓冲区被重复使用时,什么也不会发生。我已经通过使用不合理的大量缓冲区(50000多个)证明了这一点,该缓冲区产生的1秒哔哔声大约是我预期的水平。这对于给定的采样率是正确的。但是,一旦所有初始缓冲区播放一次,样本将停止。

    我尝试过使用内部循环以外的运行循环。我已经检查了我的回调是否被调用,是否接收到正确的对象,并且似乎正在为缓冲区的内容设置正确的值,但它只是停止工作。也没有任何AudioQueue函数返回任何异常OSStatus代码。我在基本描述中尝试了各种选项来解释数据格式和尾数。我只是想不出还有什么是错误的,因为我所拥有的与我所发现的大多数例子相似。

    (注意:为了简洁起见,我省略了启动和停止音频队列的命令。我只想说一句 createAudioQueue() 这就是所谓的

    func synthesizerCallback(userData: UnsafeMutableRawPointer?, audioQueue: AudioQueueRef, buffer: AudioQueueBufferRef) {
        guard let rawSynth = userData else { return }
        let synth = Unmanaged<Synthesizer>.fromOpaque(rawSynth).takeUnretainedValue()
        synth.write(withAudioQueue: audioQueue, toBuffer: buffer)
    }
    
    class Synthesizer {
    
        enum Errors: Error {
            case coreAudioError(OSStatus)
            case couldNotInitialiseAudioQueue
        }
    
        private var format: AudioStreamBasicDescription
        private var outputQueue: AudioQueueRef?
        private var outputBuffers: [AudioQueueBufferRef?]
        private var offset: Double = 0
    
        let sampleRate: Double
        let channels: Int
    
        init(sampleRate: Double = 44100, channels: Int = 2, bufferCount: Int = 3) {
            assert(bufferCount > 2, "Need at least three buffers!")
    
            self.sampleRate = sampleRate
            self.channels = channels
            self.outputBuffers = Array<AudioQueueBufferRef?>(repeating: nil, count: bufferCount)
    
            let uChannels = UInt32(channels)
            let channelBytes = UInt32(MemoryLayout<Int16>.size)
            let bytesPerFrame = uChannels * channelBytes
    
            self.format = AudioStreamBasicDescription(
                mSampleRate: Float64(sampleRate),
                mFormatID: kAudioFormatLinearPCM,
                mFormatFlags: kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked,
                mBytesPerPacket: bytesPerFrame,
                mFramesPerPacket: 1,
                mBytesPerFrame: bytesPerFrame,
                mChannelsPerFrame: uChannels,
                mBitsPerChannel: channelBytes * 8,
                mReserved: 0
            )
        }
    
        private func createAudioQueue() throws {
            let selfPointer = unsafeBitCast(self, to: UnsafeMutableRawPointer.self)
            let createOutputResult = AudioQueueNewOutput(&format, synthesizerCallback, selfPointer, nil, nil, 0, &outputQueue)
    
            if createOutputResult != 0 { throw Errors.coreAudioError(createOutputResult) }
            guard let outputQueue = outputQueue else { throw Errors.couldNotInitialiseAudioQueue }
    
            for i in 0 ..< outputBuffers.count {
                let createBufferResult = AudioQueueAllocateBuffer(outputQueue, format.mBytesPerFrame, &outputBuffers[i])
                if createBufferResult != 0 { throw Errors.coreAudioError(createBufferResult) }
                guard let outputBuffer = outputBuffers[i] else { throw Errors.couldNotInitialiseAudioQueue }
                synthesizerCallback(userData: selfPointer, audioQueue: outputQueue, buffer: outputBuffer)
            }
    
            let primeQueueResult = AudioQueuePrime(outputQueue, 0, nil)
            if primeQueueResult != 0 { throw Errors.coreAudioError(primeQueueResult) }
    
            let startQueueResult = AudioQueueStart(outputQueue, nil)
            if startQueueResult != 0 { throw Errors.coreAudioError(startQueueResult) }
        }
    
        func write(withAudioQueue audioQueue: AudioQueueRef, toBuffer buffer: AudioQueueBufferRef) {
            let dataSize = MemoryLayout<Int16>.stride * channels
            let phase = offset / sampleRate * 10000 * Double.pi * 2
            let value = Int16(sin(phase) * Double(Int16.max))
            var allChannels = Array<Int16>(repeatElement(value, count: channels))
    
            buffer.pointee.mAudioData.copyMemory(from: &allChannels, byteCount: dataSize)
            buffer.pointee.mAudioDataByteSize = UInt32(dataSize)
    
            let enqueueResult = AudioQueueEnqueueBuffer(audioQueue, buffer, 0, nil)
            if enqueueResult != 0 { print(enqueueResult) }
    
            offset += 1
        }
    
    }
    

    使现代化

    0 回复  |  直到 7 年前
    推荐文章