iOS:如何在没有fps丢弃的情况下播放音频?

时间:2016-07-20 14:33:54

标签: ios swift audio avaudioplayer audiokit

我正在使用Sprite Kit开发适用于iOS 9+的游戏,最好使用Swift库。

目前我正在使用Singleton预装我的音频文件,每个音频文件都连接到一个单独的AVAudioPlayer实例。

这是一个简短的代码 - 剪切以获得想法:

import SpriteKit
import AudioToolbox
import AVFoundation

class AudioEngine {

    static let sharedInstance = AudioEngine()

    internal var sfxPing: AVAudioPlayer

    private init() {

        self.sfxPing = AVAudioPlayer()

        if let path = NSBundle.mainBundle().pathForResource("ping", ofType: "m4a") {
            do {
                let url = NSURL(fileURLWithPath:path)
                sfxPing = try AVAudioPlayer(contentsOfURL: url)
                sfxPing.prepareToPlay()
            } catch {
                print("ERROR: Can't load ping.m4a audio file.")
            }
        }

    }

}

在应用启动期间初始化此Singleton。在游戏循环中,我只需调用以下行来播放特定的音频文件:

AudioEngine.sharedInstance.sfxPing.play()

这基本上有效,但在播放文件时我总是会出现故障,并且我的iPad Air上的帧速率从60.0降到56.0。

有人知道如何使用AVAudioPlayer修复此性能问题吗?

我还看了第三方图书馆,即:

要求:

  • 播放很多非常短的样本(如镜头,点击等)。
  • 播放一些电机效果(因此投球会很好)
  • 在循环中播放一些背景/环境声音
  • 没有令人讨厌的故障/帧速率下降!

您能否根据我的要求推荐上述任何库,或使用上述代码指出问题?

更新

播放短音:

self.runAction(SKAction.playSoundFileNamed("sfx.caf", waitForCompletion: false))

确实提高了帧速率。 I exported the audio files with Audiacity to the .caf format (Apple's Core Audio Format).但是在教程中,它们使用“Signed 32-bit PCM”编码导出,导致我的情况下音频播放受到干扰。使用任何其他编码选项(32-bit floatU-LawA-Law等。)对我来说很好。

为什么要使用caf格式?因为与m4a等压缩格式相比,它没有压缩,因此加载到内存中的速度更快,CPU开销更少。对于在短时间间隔内播放很多的短音效,这是有道理的,并且对于消耗几千字节的短音频文件,磁盘使用不会受到太大影响。对于较大的音频文件,如环境音乐和背景音乐,使用压缩格式(mp3m4a)显然是更好的选择。

1 个答案:

答案 0 :(得分:3)

根据您的问题,如果您开发适用于iOS 9+的游戏,则可以使用新的iOS 9库 SKAudioNode official Apple doc):

var backgroundMusic: SKAudioNode!

例如,您可以将其添加到didMoveToView()

if let musicURL = NSBundle.mainBundle().URLForResource("music", withExtension: "m4a") {
    backgroundMusic = SKAudioNode(URL: musicURL)
    addChild(backgroundMusic)
}

您还可以用来播放简单的效果:

let beep = SKAudioNode(fileNamed: "beep.wav")
beep.autoplayLooped = false
self.addChild(beep)

最后,如果你想改变音量:

beep.runAction(SKAction.changeVolumeTo(0.4, duration: 0))

<强>更新

我发现您更新了有关AVAudioPlayerSKAction的问题。我已经为我的iOS8 +兼容游戏测试了它们。

关于AVAudioPlayer,我个人使用我基于旧SKTAudio制作的自定义库。

我看到你的代码,关于AVAudioPlayer init,我的代码是不同的,因为我使用:

@available(iOS 7.0, *)
    public init(contentsOfURL url: NSURL, fileTypeHint utiString: String?)

我不知道fileTypeHint是否有所作为,所以请尽量让我知道你的考试。

您的代码的优势: 使用基于AVAudioPlayer的共享实例音频管理器,您可以控制音量,随时随地使用您的经理,确保与iOS8的兼容性

您的代码的缺点: 每当你播放声音并想要播放另一种声音时,前一段声音就会被打破,特别是如果你发布了背景音乐。

如何解决?根据此SO post运行良好而没有问题似乎AVFoundation仅限于4个AVAudioPlayer属性可实例化,因此您可以执行此操作:

  • 1)backgroundMusicPlayer:AVAudioPlayer!
  • 2)soundEffectPlayer1:AVAudioPlayer!
  • 3)soundEffectPlayer2:AVAudioPlayer!
  • 4)soundEffectPlayer3:AVAudioPlayer!

您可以构建一个方法来切换3声音效果以查看是否被占用:

if player.playing

并使用下一个免费播放器。通过这种解决方法,您可以始终正确地播放声音,甚至是背景音乐。