通过iOS(Swift)中的AVAudioPlayerNode *在模拟器中工作,但在设备上没有缓冲区播放的可听到的故障

时间:2015-03-10 18:39:43

标签: ios swift audio avaudiopcmbuffer avaudioplayernode

当使用AVAudioPlayerNode安排短暂的缓冲区在触摸事件中立即播放时(" Touch Up Inside"),我在测试时发现了回放时可听到的毛刺/瑕疵。在iOS模拟器中,音频根本不会出现故障,但是当我在实际的iOS设备上运行应用程序时,播放时会出现听觉失真。可听见的失真是随机发生的(触发的声音有时听起来很棒,而其他时候声音会失真)

我尝试使用不同的音频文件,文件格式以及准备缓冲区以使用prepareWithFrameCount方法进行播放,但遗憾的是结果始终相同,我不知道可能出现什么问题。

为了清晰和简单,我已将代码删除为全局变量。任何帮助或见解将不胜感激。这是我开发iOS应用程序的第一次尝试,也是我在Stack Overflow上发布的第一个问题。

let filePath = NSBundle.mainBundle().pathForResource("BD_withSilence", ofType: "caf")!
let fileURL: NSURL = NSURL(fileURLWithPath: filePath)!
var error: NSError?
let file = AVAudioFile(forReading: fileURL, error: &error)

let fileFormat = file.processingFormat
let frameCount = UInt32(file.length)
let buffer = AVAudioPCMBuffer(PCMFormat: fileFormat, frameCapacity: frameCount)

let audioEngine = AVAudioEngine()
let playerNode = AVAudioPlayerNode()

func startEngine() {

    var error: NSError?
    file.readIntoBuffer(buffer, error: &error)
    audioEngine.attachNode(playerNode)
    audioEngine.connect(playerNode, to: audioEngine.mainMixerNode, format: buffer.format)
    audioEngine.prepare()

    func start() {
        var error: NSError?
        audioEngine.startAndReturnError(&error)
    }

    start()

}

startEngine()

let frameCapacity = AVAudioFramePosition(buffer.frameCapacity)
let frameLength = buffer.frameLength
let sampleRate: Double = 44100.0

func play() {

    func scheduleBuffer() {
    playerNode.scheduleBuffer(buffer, atTime: nil, options: AVAudioPlayerNodeBufferOptions.Interrupts, completionHandler: nil)
    playerNode.prepareWithFrameCount(frameLength)
    }

    if playerNode.playing == false {
        scheduleBuffer()
        let time = AVAudioTime(sampleTime: frameCapacity, atRate: sampleRate)
        playerNode.playAtTime(time)
    }
    else {
        scheduleBuffer()
    }
}

// triggered by a "Touch Up Inside" event on a UIButton in my ViewController

@IBAction func triggerPlay(sender: AnyObject) {
   play()
}

更新

好的我认为我已经确定了失真的来源:节点的音量在输出时太大并导致削波。通过在我的startEngine函数中添加这两行,不再发生失真:

playerNode.volume = 0.8
audioEngine.mainMixerNode.volume = 0.8

但是,我还不知道为什么我需要降低输出 - 我的音频文件本身不会剪辑。我猜测它可能是AVAudioPlayerNodeBufferOptions.Interrupts实现方式的结果。当缓冲区中断另一个缓冲区时,由于中断会导致输出量增加,从而导致输出削波?我仍然在寻找一个可靠的理解为什么会发生这种情况。如果有人愿意/能够提供任何关于此的澄清,这将是太棒了!

1 个答案:

答案 0 :(得分:0)

不确定这是否是您在2015年遇到的问题,可能与@suthar在2018年遇到的问题相同。

我遇到了一个非常相似的问题,这是由于设备上的sampleRate与模拟器不同。在macOS上是44100,在iOS设备(最新型号)上是48000。

因此,当在48000台设备上用44100个样本填充缓冲区时,您将获得3900个静默样本。播放时听起来不像是沉默,听起来像是小故障。

在连接playerNode以及创建pcmBuffer时,我使用了mainMixer格式。不要在代码中的任何地方引用48000或44100。

    audioEngine.attach( playerNode)
    audioEngine.connect( playerNode, to:mixerNode, format:mixerNode.outputFormat(forBus:0))

    let pcmBuffer = AVAudioPCMBuffer( pcmFormat:SynthEngine.shared.audioEngine.mainMixerNode.outputFormat( forBus:0),
                                      frameCapacity:AVAudioFrameCount(bufferSize))