【问题标题】:What do you use to play sound in iPhone games?你用什么在 iPhone 游戏中播放声音?
【发布时间】:2010-11-02 11:40:21
【问题描述】:

我有一款性能密集型 iPhone 游戏,我想为其添加声音。似乎有大约三个主要选择:(1)AVAudioPlayer,(2)音频队列和(3)OpenAL。我讨厌写几页低级代码只是为了播放示例,所以我想使用AVAudioPlayer。问题是它似乎扼杀了性能——我使用CFAbsoluteTimeGetCurrent 做了一个简单的测量,play 消息似乎需要 9 到 30 毫秒才能完成。考虑到 25 ms == 40 fps,这真是太悲惨了。

当然有prepareToPlay 方法可以加快速度。这就是为什么我编写了一个简单的类,它保留了几个 AVAudioPlayers 供其使用,预先准备好它们,然后使用准备好的播放器播放样本。没有雪茄,仍然需要我上面提到的大约 20 毫秒。

这样的性能在游戏中是无法使用的,那么你用什么来在 iPhone 上播放性能不错的声音呢?我对AVAudioPlayer 做错了吗?您是否使用音频队列播放声音? (在 2.2 发布之前,我已经写过类似于 AVAudioPlayer 的东西,我很乐意保留这种经验。)你使用 OpenAL 吗?如果是,是否有一种简单的方式来使用 OpenAL 播放声音,或者您是否必须编写代码页?


更新:是的,使用 OpenAL 播放声音是 fairly simple


【问题讨论】:

  • Finch 使用什么声音格式?我尝试了一个 16 位、44.1kHz、PCM(未压缩)的 .caf 文件,播放声音时发出嘶嘶声。
  • 事实证明 OpenAL 需要 little-endian 数据。我使用的转换器应用程序,只保存大端。切换到 afconvert 直到我可以编写拖放转换器。
  • 是 finch 缓冲音频文件还是我们应该明确缓冲它。
  • 整个音频缓冲区在播放前被发送到 OpenAL,所以我认为在调用端进行缓冲没有什么意义。
  • 你确定你的意思不是~200毫秒吗? 20 毫秒是一个非常短的时间,当然对于游戏声音来说已经足够了......

标签: iphone performance audio avaudioplayer finch


【解决方案1】:

AVAudioPlayer 对于游戏音频来说是非常边缘化的。通过改编其中一个示例来处理 AudioQueue 或 OpenAL 绝对是要走的路。这种方式的延迟更可控。

【讨论】:

  • AVAudioPlayer 自 2009 年以来有了很大改进。
  • 您好,我来自 2018 年,AVAudioPlayer 如果反复调用 playsetCurrentTime:0,帧率仍然会下降。 dispatch_async 没有帮助。 .caf 扩展也无济于事。
【解决方案2】:

如果您在主线程上调用play,请尝试在单独的线程上运行它。我最终做的是:

#include <dispatch/dispatch.h>

dispatch_queue_t playQueue = dispatch_queue_create("com.example.playqueue", NULL);

AVAudioPlayer* player = ...
dispatch_async(playQueue, ^{
    [player play];
});

这解决了我遇到的最严重的帧速率卡顿问题。

【讨论】:

    【解决方案3】:

    我使用 OpenAL 和 CrashLanding 示例代码附带的类。到目前为止,它可以同时播放样本和循环播放音乐。我目前正在学习如何释放为声音(.wav 文件)分配的内存,例如,当我只想播放一些介绍音乐时。

    【讨论】:

    • 我害怕 Crash Landing 中的音频代码,这就是我寻找替代方案的原因。毕竟,封装一个简单的 OpenAL 类非常容易——你可以看看我编写的代码,看看它是否比 Crash Landing 中的声音引擎更适合。
    【解决方案4】:

    使用CocosDenshion - 它免费、简单且有效。它包含 AVAudioPlayer 用于背景音轨和 OpenAL 用于声音。

    【讨论】:

      【解决方案5】:

      您想检查正在使用的实现的缓冲吗?这可能与您遇到的 20 毫秒延迟有关。即,尝试调整缓冲区大小。

      【讨论】:

      • 什么样的缓冲? (抱歉,如果问题不清楚。)我目前正在使用香草 AVAudioPlayer,只是带有一个包装器,可以让几个播放器保持在手边,每次其中一些播放器完成时,包装器都会调用 prepareToPlay 方法。
      • 在某些时候,应该将音频数据读入缓冲区以便播放,寻找它并尝试调整缓冲区大小。
      • 我刚刚检查了API,当你初始化并使用initWithData时,尝试指定一个足够大的内存缓冲区。
      • 啊哈。我不认为 AVAudioPlayer 让你这样做。缓冲区大小很可能是根据数据格式自动检测的,第一个缓冲区在您调用 prepareToPlay 时已准备好。
      • 嗯。如果您正在流式传输音频,那将是一种糟糕的方式。对不起,我不能帮助你。等待另一个回应或尝试不同的方法。问题的 OpenAL 处理方法在这里:gehacktes.net/2009/03/…
      猜你喜欢
      • 1970-01-01
      • 2010-10-11
      • 2011-08-01
      • 2010-09-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多