播放AVAudioPlayers经常导致SIGSEGV?

时间:2014-03-19 23:20:38

标签: c# xamarin.ios avaudioplayer sigsegv xamarin-studio

我正在Xamarin工作室开发一款iOS游戏,并且遇到了崩溃问题。一个 SIGSEGV 。我正在使用 AVAudioPlayer 播放音效。基本上我给了一个士兵真正快速射击的能力!当压力测试这种能力时,我已经遇到了SIGSEGV。我可以成功地在我的项目中重现它。基本上,如果我评论所有声音效果播放,崩溃永远不会发生。如果我留下声音效果,崩溃就会发生。

我的项目崩溃只给我这个:

2014-03-19 18:03:08.304 CyCom[5666:131a3] 18:03:08.303 ERROR:     >aqsrv> 65: Exception caught in (null) - error -66634
mono-rt: Stacktrace:


mono-rt:   at <unknown> <0xffffffff>

mono-rt:   at (wrapper managed-to-native) MonoTouch.UIKit.UIApplication.UIApplicationMain (int,string[],intptr,intptr) <IL 0x0009f, 0xffffffff>

mono-rt:   at MonoTouch.UIKit.UIApplication.Main (string[],string,string) [0x0004c] in /Developer/MonoTouch/Source/monotouch/src/UIKit/UIApplication.cs:38

mono-rt:   at CyCom.Application.Main (string[]) [0x00012] in /Users/jzacherl/Projects/CyCom/CyCom/CyCom/Main.cs:20

mono-rt:   at (wrapper runtime-invoke) <Module>.runtime_invoke_void_object (object,intptr,intptr,intptr) <IL 0x00050, 0xffffffff>

mono-rt: 
Native stacktrace:


mono-rt: 

Got a SIGSEGV while executing native code. This usually indicates
a fatal error in the mono runtime or one of the native libraries 
used by your application.

重要的是要注意,此崩溃只发生在iOS模拟器上。我无法在iPad设备上重现此崩溃。这可能是一个线程计时的东西或垃圾收集的东西,但我只是猜测那里。

我尝试在单独的项目located here 中复制此内容,但未获成功。我无法通过相同/类似的消息使其崩溃。很明显,我的主要项目和这个测试项目之间有一百万个差异(这可能就是为什么我无法在测试项目中重现它),但是我无法帮助而是感觉玩这个声音效果如此之多/快速导致了这一点。

Here is a video of me demonstrating this crash 即可。在这个视频中,我演示了声音打开,当我发送垃圾声音效果时,我最终崩溃了这个错误。然后我演示关闭声音效果我不会因此错误而崩溃。

以下是我的Play Sound功能之一的代码片段,以及[a file containing lots of them][3]

    public static AVAudioPlayer GetNextAudioPlayer_General( )
    {
        // The UIApplicationDelegate for the application.
        AppDelegate appDel = (AppDelegate)UIApplication.SharedApplication.Delegate;

        // The first thing I need to do is take ownership of the next player in the SoundEffectPlayerList.  To do this, simply increment the index so no other thread can have this player.  
        // If this thread is grabbing index 7, and inc the endex, the next thread that trys to access it will get 8...  That's why I inc the index ahead of time rather than after....  It's a multi threading bug prevention thing

        AVAudioPlayer player = null;
        lock(appDel.CyCom.battlefield.SoundEffectPlayerList_General)
        {
            player = appDel.CyCom.battlefield.SoundEffectPlayerList_General[appDel.CyCom.battlefield.SoundEffectPlayerList_General_Index];

            // Inc the index
            appDel.CyCom.battlefield.SoundEffectPlayerList_General_Index++;
            if ( appDel.CyCom.battlefield.SoundEffectPlayerList_General_Index >= appDel.CyCom.battlefield.SoundEffectPlayerList_General.Count )
            {
                appDel.CyCom.battlefield.SoundEffectPlayerList_General_Index = 0;
            }
        }

        return player;
    }


    public static void PlaySoundEffect_FireWeapon ( MySoldier soldier )
    {
        AppDelegate appDel = (AppDelegate)UIApplication.SharedApplication.Delegate;

        // If Audio is enabled and the gamespeed is within limits
        if ( appDel.globals.AudioEnabled && appDel.CyCom.GameSpeed <= appDel.globals.Audio_MaxGameSpeedThatAllowsAudioToPlay )
        {
            // Play Weapon Fire Audio
            AVAudioPlayer audioPlayer = Library_Sounds.GetNextAudioPlayer_General();

            // Set up the Audio Player with the sound effect to be played
            if ( soldier.Attributes.Weapon.WeaponType == appDel.globals.SoldierModelWeaponType_Rifle )
            {
                audioPlayer = AVAudioPlayer.FromData(appDel.CyCom.SoundEffects.MediaFile_SoundEffects_M4_Fire);
            }
            else if ( soldier.Attributes.Weapon.WeaponType == appDel.globals.SoldierModelWeaponType_WarheadLauncher )
            {
                audioPlayer = AVAudioPlayer.FromData(appDel.CyCom.SoundEffects.MediaFile_SoundEffects_Rocket_Launch_01);
            }

            // Set the volume
            audioPlayer.Volume = soldier.PlayerVolume;
            audioPlayer.Play();
        }
    }

关于罗尔夫的评论:Here's a link to the ASI file from the Mac Console app

关于罗尔夫的评论:Here's the .crash file

关于Choper的评论:我替换了每个Player.Play();使用以下代码:

PlayThisAudioPlayer(player);

以下是功能:

public static void PlayThisAudioPlayer( AVAudioPlayer player )
    {
        AppDelegate appDel = (AppDelegate)UIApplication.SharedApplication.Delegate;

        player.FinishedPlaying += CreateFinishedPlayingEvent(player);

        player.Play();
    }


    public static EventHandler<AVStatusEventArgs> CreateFinishedPlayingEvent ( AVAudioPlayer player )
    {
        EventHandler<AVStatusEventArgs> finishedPlayingEvent;
        finishedPlayingEvent = delegate(object sender, AVStatusEventArgs e) {
            player.Stop();
            player.FinishedPlaying -= finishedPlayingEvent;
            player.Dispose();
            player = null;
        };

        return finishedPlayingEvent;
    }

我现在正在崩溃:

2014-03-20 11:09:37.568 CyCom[5533:a0b] EXCEPTION IN THE MAIN.CS
2014-03-20 11:09:37.569 CyCom[5533:a0b] the player object was Dispose()d during the callback, this has corrupted the state of the program
2014-03-20 11:09:37.569 CyCom[5533:a0b]   at MonoTouch.AVFoundation.InternalAVAudioPlayerDelegate.FinishedPlaying (MonoTouch.AVFoundation.AVAudioPlayer player, Boolean flag) [0x00032] in /Developer/MonoTouch/Source/maccore/src/AVFoundation/Events.cs:72 
at (wrapper managed-to-native) MonoTouch.UIKit.UIApplication:UIApplicationMain (int,string[],intptr,intptr)
at MonoTouch.UIKit.UIApplication.Main (System.String[] args, System.String principalClassName, System.String delegateClassName) [0x0004c] in /Developer/MonoTouch/Source/monotouch/src/UIKit/UIApplication.cs:38 
at CyCom.Application.Main (System.String[] args) [0x00013] in /Users/jzacherl/Projects/CyCom/CyCom/CyCom/Main.cs:23 

附加虽然:我认为问题可能在于我使用静态功能....现在试着证明这是真是假。

我给了Choper这里的复选标记因为问题最终导致我重复使用AVAudioplayers而不是放弃它们。无论出于何种原因,您都无法长时间重复使用AVAudioplayers。我不明白为什么,但它被证明是坏事!我重新设计了我的代码,以便AVAudio播放器在需要时创建,然后由后台线程处理。

1 个答案:

答案 0 :(得分:1)

将这一个添加到您的代码中:

audioPlayer.FinishedPlaying += HandleAudioFinished;

...

private void HandleAudioFinished (object sender, AVStatusEventArgs e) 
{
    if (audioPlayer != null)
    {
        audioPlayer.Stop();
        audioPlayer.FinishedPlaying -= HandleAudioFinished;
        audioPlayer.Dispose();
        audioPlayer = null;
    }
}