MonoTouch:播放声音

4
我正在尝试在用户点击特定按钮时播放短音频。但问题是我总是收到“Object reference not set to an instance object”,意思是空值!我先尝试了MonoTouch.AudioToolBox.SystemSound。
MonoTouch.AudioToolbox.AudioSession.Initialize();   
MonoTouch.AudioToolbox.AudioSession.Category = MonoTouch.AudioToolbox.AudioSessionCategory.MediaPlayback;   
MonoTouch.AudioToolbox.AudioSession.SetActive(true);   

var t = MonoTouch.AudioToolbox.SystemSound.FromFile("click.mp3");
t.PlaySystemSound();

请注意,"click.mp3"位于根解决方案文件夹中,并标记为内容。 另一种方法是使用MonoTouch.AVFoundation.AVAudioPlayer。
var url = NSUrl.FromFilename("click.mp3");
AVAudioPlayer player = AVAudioPlayer.FromUrl(url);
player.FinishedPlaying += (sender, e) => { player.Dispose(); };
player.Play();

但是仍然出现了相同的错误。我在谷歌上搜索发现很多人也遇到了这个问题。我们需要知道这是否是一个错误。


注意:在iOS7中,上面的前三行(Initialize、Category、SetActive)已被弃用,不使用它们也可以正常工作。 - Ender2050
3个回答

7
关于如何使用SystemSoundMP3,请参考这个问题和答案:Playing a Sound With Monotouch 对于AVAudioPlayer,请注意以下模式是危险的:
AVAudioPlayer player = AVAudioPlayer.FromUrl(url);
player.FinishedPlaying += (sender, e) => { player.Dispose(); };
player.Play();

自从播放是异步的,这意味着管理的player实例可能在FinishedPlaying发生之前就已经超出范围。反过来,这个超出范围意味着GC可能已经收集了该实例。

解决此问题的方法是将player本地变量提升为类型字段。这将确保在播放声音时GC不会收集实例。

玩家在回调发生之前不会被处理。操作系统对回调lambda有一个活动引用(必须这样做,以便在播放完成时实际执行回调)。在该引用消失之前,玩家本身仍然处于活动对象图中。在调用player.Dispose()之后,player就可以进行垃圾回收了,但在此之前不行。 - James Moore

4

你的代码看起来是正确的(我与这里的代码进行了比较,可以播放音频)。

问题可能在于音频文件没有以某种方式包含在应用程序包中。您可以使用以下代码轻松检查:

if (!System.IO.File.Exists ("click.mp3"))
    Console.WriteLine ("bundling error");

太棒了!你是对的。我尝试了你的方法,发现这个文件不存在。所以我再次检查了文件,现在发现它没有被标记为内容。我进行了更改,但它仍然无法工作。我删除了obj文件夹,问题终于解决了。谢谢。 - Peyman
仍然对我无效。声音文件存在。我设置了一个断点。我的 sound.PlaySystemSound() 行被触发,而且 sound 是 SystemSound 的有效实例。我的设备音量已经调到最大。我的声音不播放。就是这样。我开始真的讨厌 Xamarin.iOS,因为它几乎从来没有按照它所说的去做,即使在最简单的情况下也是如此。 - Perrin Larson

1
在大多数情况下,问题是文件不存在。如果您和我一样,已经确保文件存在,请确保以下内容:
  1. 文件路径应该是相对于您的类(即:Sounds\beep.wav)(绝对路径在模拟器上无法工作)
  2. 确保在类级别中定义了SoundSystem。这是因为MT有一个非常激进的垃圾回收器,甚至可能在播放之前就释放了您的SoundSystem。请参见此链接

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