AVAudioPlayerNode的音量更改不会立即应用

4
使用AVFoundation和AVAudioPlayerNode在Xcode版本9.2(9C40b)上播放声音并部署到iOS 11.2。当你更改音量时,问题在于第一次播放声音时不会应用此更改,并且存在其他奇怪的影响。
在Xcode中启动一个新项目,选择iOS游戏并赋予任何名称。然后将GameScene.swift中的代码替换为:
import SpriteKit
import GameplayKit
import AVFoundation

class GameScene: SKScene {

    var entities = [GKEntity]()
    var graphs = [String : GKGraph]()

    let audioFilePlayer = AVAudioPlayerNode()
    var audioFile:AVAudioFile! = nil
    var audioFileBuffer:AVAudioPCMBuffer! = nil

    override func sceneDidLoad() {
        do {
            let path = Bundle.main.path(forResource: "sound", ofType: "caf")!
            let url = URL(fileURLWithPath: path)
            audioFile = try AVAudioFile(forReading: url)
            audioFileBuffer = AVAudioPCMBuffer(pcmFormat: audioFile.processingFormat, frameCapacity: UInt32(audioFile.length))
            try audioFile.read(into: audioFileBuffer!)
            audioEngine.attach(audioFilePlayer)
            audioEngine.connect(audioFilePlayer, to: audioEngine.mainMixerNode, format: audioFileBuffer?.format)
            try audioEngine.start()
        }
        catch {
            print(error)
        }

        let playAction = SKAction.sequence([
            SKAction.wait(forDuration: 3.0),
            SKAction.run { self.play(volume: 1.0) },
            SKAction.wait(forDuration: 1.0),
            SKAction.run { self.play(volume: 1.0) },
            SKAction.wait(forDuration: 1.0),
            SKAction.run { self.play(volume: 0.0) },
            SKAction.wait(forDuration: 1.0),
            SKAction.run { self.play(volume: 0.0) },
            SKAction.wait(forDuration: 1.0),
            SKAction.run { self.play(volume: 1.0) },
            SKAction.wait(forDuration: 1.0),
            SKAction.run { self.play(volume: 1.0) },
            ])
        self.run(playAction)

    }

    func play(volume:Float) {
        print("playing at \(volume)")
        audioFilePlayer.stop()
        audioFilePlayer.volume = volume
        audioFilePlayer.scheduleFile(audioFile, at: nil, completionHandler: nil)
        audioFilePlayer.play()
    }

}

抱歉,可选项不够清晰...同时,在项目中添加名为sound.caf的音频文件。

控制台输出为:

playing at 1.0
playing at 1.0
playing at 0.0
playing at 0.0
playing at 1.0
playing at 1.0

我期望听到的是:响亮的,响亮的,没有声音,没有声音,响亮的,响亮的。
实际上我听到的是:响亮的,响亮的,响亮的,没有声音,轻微的,响亮的。(特别奇怪的是"轻微的")
我也尝试过使用以下方法改变主音量:
audioEngine.mainMixerNode.outputVolume = volume

但是声音都是一样的。

在旧游戏中,使用OpenAL,但这需要Obj-C,并且与桥接头等非常混乱。此外,据说OpenAL不再受支持。基于SKAction的音频无法处理大量快速重复的声音,会出现故障和划痕(这是一个太空射击游戏...)问题在模拟器和设备上都是相同的。感谢任何帮助!

2个回答

2

好的,我找到了答案。在音量变化后,需要重置AudioEngine才能使更改立即生效:

audioEngine.reset()

这个play()函数能够正常工作:
    func play(volume:Float) {
        print("playing at \(volume)")
        audioFilePlayer.volume = volume
        audioEngine.reset()
        audioFilePlayer.stop()
        audioFilePlayer.scheduleFile(audioFile, at: nil, completionHandler: nil)
        audioFilePlayer.play()
    }

请纠正我,但您也可以只设置audioFilePlayer.volume而不触及reset, stop, or play,输出音量应立即更改。 - Bob
我的经验是仅仅改变音量并不会改变音量,除非你也进行重置......这可能在新版本中已经改变了,现在可能可以工作。如果是这样的话,你应该添加一个答案。 - Christian Cerri
2
2020 年,Swift 5 中仍无法在播放过程中调整播放器节点的音量。停止播放、重置、调整音量,然后重新开始并非解决方案... 然而,我找到了一种替代方法。通过此链接了解如何在播放过程中进行调整。我需要调整均衡器设置。也许使用 AVAudioEQ 的 globalGain 方法能帮助你。https://www.hackingwithswift.com/example-code/media/how-to-control-the-pitch-and-speed-of-audio-using-avaudioengine - SouthernYankee65
@SouthernYankee65,你能分享一下解决方案吗? - Varun Naharia
很遗憾,我放弃了使用AVAudioEngine和节点的方法。但是我认为在追求这种方法时,我使用了AVAudioUnitEQ上的globalGain方法通过计时器执行淡入淡出效果。抱歉我无法提供更多帮助。 - SouthernYankee65

1

没错,如果还有其他人感兴趣的话,我也通过在输入源和engine.mainMixerNode之间添加AVAudioMixerNode来解决了这个问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接