SoundEffects do not recover from iOS interruptions

I’m finding that when I call my test iPhone, after my game resumes, I do not get sound effects (they work fine until this interruption).

Having trawled the forums old and new, I found this and this, the former of which mentions a possible solution, which I could not see implemented anywhere in Monogame 3.2. I tried playing with AVAudioSession.SharedInstance().EndInterruption event, but this just caused my game to crash when the call came in.

Anyone know anything more about this?

I was the OP (“theremin”) for that second link. For what it’s worth, I gave up on MonoGame sound effects and I’m currently using a version of ObjectAL built for Xamarin.iOS instead. I stripped out all of the audio code from MonoGame, and ObjectAL has been far more reliable for recovering from sound effect interruptions for me (at least on iOS 7; there are still some issues on iOS 5 and 6).

I asked a couple MonoGame people on Twitter about this, and unfortunately it sounds like whoever wrote the iOS sound code isn’t really involved with MonoGame anymore, and they don’t have any immediate plans (or the required knowledge) to fix this.

I will say, back when I was looking into this, I never did see that first link you found. That’s very interesting. I’m pretty sure the way to fix this is going to be adding calls to Alc.MakeContextCurrent as described by johnHolmes in your first link. Unfortunately, I’m pretty sure OpenALSoundController has no concept of being deactivated/suspended, so when its context is set to NULL, things are going to start to blow up.

I would love to look into this myself, but my wife just had a baby, so all of my spare time for gamedev has vanished for the time being. If you decide you’d like to investigate this issue further and try to submit a fix to MonoGame (which would be awesome, I would love to see this get fixed), I’d be more than happy to chat with you over e-mail. Feel free to get in touch with me. I just don’t have time to dig too deeply into it myself right now.

This is hilarious. I’ve posted the solution several months ago and they didn’t merged it? I also managed some other fixes which were ignored by team…

Don’t suppose you’ve still got details of/code for your solution?

I’ve contacted picobots about the OpenAL solution they’ve used, but would like to stay within Monogame if possible - I’m also now about a month away from my launch deadline, so tinkering with my own OpenAL solution or the guts of Monogame is not really an option, especially considering that I’ll probably need a couple of weeks of that for App Store certification to clear…

You just need to change the MG source as described in my post and it should work!

@johnHolmes: When you say you posted the solution several months ago, are you talking about what you described in this post from over 2 years ago? Or is there a newer solution somewhere? Did you ever submit it to GitHub? If it really is that easy, I can take a stab at implementing your changes and submitting it—although it looks like that older solution was for MonoGame 2.5, so who knows if it will still work for MonoGame 3.

@Ben_P1: I’d be happy to share my ObjectAL DLL if you’d like to try it in your project. Note: This is a .NET/Xamarin port of ObjectAL—that’s ObjectAL, not OpenAL—which is an open source library written in Objective-C by Karl Stenerud to try to help iOS developers with their audio code. But it doesn’t play nicely with MonoGame’s sound code, so you have to go through and comment out a bunch of MonoGame sound code files (I can’t remember which ones—OpenALSoundController maybe, and possibly some others).

Here’s a link to my port of ObjectAL, which you can just include as a reference in your project and then use according to the ObjectAL documentation:
http://www.mediafire.com/download/cv40gwhu9144fd7/ObjectALBinding.dll

If you’re looking for Xamarin/MonoTouch-specific documentation, check out this GitHub project, which is a much older version of the same thing (a Xamarin port of ObjectAL). I simply rebuilt the project from the latest ObjectAL source.

@JohnHolmes - the AudioSession object does not exist in OpenALSoundController within the current version of Monogame.

What namespace should this be under? Just wondering if it can be plugged back in, or whether there’s been a fundamental re-working of the way iOS sound effects are handled.

Yeah, I looked into this briefly, and although you might be able to hack a solution in place using the code that @johnHolmes provided, I think it’s going to be a bit trickier to make a forward-looking solution that can safely be committed to MonoGame.

The AudioSession he’s referencing is Apple’s old AudioSession class (which has been deprecated since iOS 6 and replaced with AVAudioSession). You’ll have to import MonoTouch.AudioToolbox to use that AudioSession code.

The problem is that AudioSession/AVAudioSession are potentially directly at odds with how MonoGame handles music and the XNA MediaPlayer class. I say “potentially” because although I understand Apple’s AudioSession classes, MonoGame uses some sort of custom MediaPlayer code (based on OpenAL perhaps?) instead of using AudioSession and AVAudioPlayer for music. I’m not sure why the MonoGame team decided to do that, but if you’re going to start using AudioSession, you’re going to want to be careful that you don’t stomp on MonoGame’s music/audio code when initialize/activate/set the category for your AudioSession. I’m not sure what happens when you start mixing and matching two different audio system paradigms. (Maybe nothing? But something to watch out for.)

Additionally, you’re going to want to be careful with how you use MediaPlayer.GameHasControl, since Apple’s AudioSession objects have their own complex way of handling that. The only safe option (as johnHolmes alluded to) is to just use AudioSessionCategory.SoloAmbientSound and always return true for MediaPlayer.GameHasControl, but that doesn’t seem like a very elegant way to handle this long term for MonoGame. Your mileage may vary, of course. Maybe a little hacked together solution will work perfectly for your game. (Fingers crossed!)

FWIW, as with sound effects, I rolled my own custom music solution using AVAudioPlayer and removed MonoGame’s music code. AVAudioSession and AVAudioPlayer are a rock solid way to play music on iOS, and they allow you to use the iPhone/iPad hardware decoder for playing mp3s so that there’s no performance hit associated with background music. I’d love to eventually rework MonoGame’s MediaPlayer code, but as I mentioned before, it seems like the iOS audio experts have long since disappeared/abandoned MonoGame, so unfortunately there isn’t anyone to help and offer advice.

I’m talking about the solution provided 2 years ago. I should have said MANY MANY months ago :slight_smile:

Listen, i will try to check the latest version of MG and see if it’s possibile to fix the thing with some “magic code”. Give me a day or two. Hope then someone plug this as a fix

@JohnHolmes - I’ve had an email from Slygamer stating that he has already implemented your solution - I’m going to test this as soon as I can, but the chances are that will not be before the weekend.

So if you or anyone else wants to take a look, check https://github.com/mono/MonoGame/pull/2938

Googling around I’ve found this article that explain the usage of OpenAL and how to handle the session/context. Maybe the MG team can give it a check to see if it’s applicable on the OpenALSoundController class.

Okay, the fix posted by Slygamer appears to work with a few modifications and caveats:

  1. AVAudioSession.SharedInstance() needs to be saved to a private variable within OpenALSoundController - otherwise it goes out of scope upon resigning the app, and causes a crash - thanks Andreyul for pointing this one out!

  2. Any music playing via MediaPlayer.Play must be stopped before the app resigns.

But having put these changes in, initial tests look (and sound) good!

And on a sound-related note, I also found that it’s worth stripping the InstancePlayLimitException that gets thrown by the SoundEffectInstance class if SoundEffectsInstancePool.SoundsAvailable is false, and instead only playing the sound if this is true, as I was getting a few crashes here - better to just not play the sound tham crash the whole game, I think.