Pregunta

I'm developing an iOS game in Xamarin Studio and am running into a crash & a SIGSEGV. I'm playing sound effects using AVAudioPlayer. Basically I gave a soldier an ability to fire really really fast! And when stress testing that ability I've been running into a SIGSEGV. I can reproduce it in my project successfully. Basically, if I comment out all sound effect plays the crash never happens. If I leave sound effect plays in, the crash happens.

My project is crashing giving me only this:

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.

It is important to note that this crash only happens on the iOS simulator. I cannot reproduce this crash on the iPad device itself. This could be a thread timing thing or a garbage collection thing, but I'm just guessing there.

I tried reproducing this in a separate project located here, but was unsuccessful. I could not get this to crash with the same/similar message. Clearly there are a million differences between my main project and this test project (likely to be why I can't get it to reproduce in the test project), but I can't help but shake the feeling that playing the sound effects so much/fast are causing this.

Here is a video of me demonstrating this crash. In this video I demonstrate that with sound turned on and when I spam sound effects, I eventually crash with this error. I then demonstrate that with sound effects turned off I do not crash with this error.

Here is a code snippet of what one of my Play Sound functions looks like, as well as [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();
        }
    }

Regarding Rolf's comment: Here's a link to the ASI file from the Mac Console app

Regarding Rolf's comment: Here's the .crash file

Regarding Choper's comment: I replaced every Player.Play(); with the following code:

PlayThisAudioPlayer(player);

And here are the functions:

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;
    }

I'm now getting this crash:

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 

Additional Though: I'm thinking the problem might be that I'm using static functions.... Trying to prove that true or false right now.

I gave Choper the checkmark here because the problem ended up being me reusing AVAudioplayers and not diposing of them. For whatever reason you cannot continuously reuse AVAudioplayers for long periods of time. I have no idea why, but it's proven to be bad! I redesigned my code such that AVAudio players are created at the time of need, then disposed of afterwards by a background thread.

¿Fue útil?

Solución

Add this one to your code:

audioPlayer.FinishedPlaying += HandleAudioFinished;

...

private void HandleAudioFinished (object sender, AVStatusEventArgs e) 
{
    if (audioPlayer != null)
    {
        audioPlayer.Stop();
        audioPlayer.FinishedPlaying -= HandleAudioFinished;
        audioPlayer.Dispose();
        audioPlayer = null;
    }
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top