This was working before the update, but now no matter what I do, the audio will not continue to play once the app is backgrounded...
Here is a snippet of my code:
Info.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<!-- removed for clarity -->
<key>MinimumOSVersion</key>
<string>6.1</string>
<key>UIBackgroundModes</key>
<array>
<string>audio</string>
</array>
</dict>
</plist>
AppDelegate.cs
using System;
using MonoTouch.AVFoundation;
using MonoTouch.Foundation;
using MonoTouch.UIKit;
using Dervish.Midi;
using Dervish.Controllers;
namespace Dervish
{
[Register ("AppDelegate")]
public partial class AppDelegate : UIApplicationDelegate
{
NSError _error;
UIWindow _window;
Metronome _metronome;
DervishViewController _viewController;
public event EventHandler<AppStateEventArgs> OnApplicationStateChanged;
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
//commented-out due to iOS 7 deprecation (not sure what the new alternative is supposed to be)
//this was working in iOS 6.1, but is now broken in iOS7, so trying AVAudioSession instead...
//AudioSession.Initialize();
//AudioSession.Category = AudioSessionCategory.MediaPlayback;
//AudioSession.OverrideCategoryMixWithOthers = true;
AVAudioSession audioInstance = AVAudioSession.SharedInstance();
//Event Handling...
audioInstance.BeginInterruption += delegate {...};
audioInstance.CategoryChanged += delegate {...};
audioInstance.EndInterruption += delegate {...};
audioInstance.OutputChannelsChanged += delegate => {...};
audioInstance.SampleRateChanged += delegate => {...};
//set audio buffer size
audioInstance.SetPreferredIOBufferDuration(0.005, out _error);
if (_error != null) {...}
audioInstance.SetActive(true, AVAudioSessionSetActiveOptions.NotifyOthersOnDeactivation, out _error);
if (_error != null) {...}
audioInstance.SetCategory(new NSString("AVAudioSessionCategoryPlayback"), out _error);
if (_error != null) {...}
_window = new UIWindow(UIScreen.MainScreen.Bounds);
_window.MakeKeyAndVisible();
_metronome = new Metronome();
_viewController = new DervishViewController(_metronome);
_window.RootViewController = _viewController;
//communicates app state change to view controller
OnApplicationStateChanged += _viewController.ApplicationStateChangeHandler;
//MIDI setup
new NSObject().BeginInvokeOnMainThread(delegate {
MidiHelper.Midi.Initialize();
});
//global exception handler...
AppDomain.CurrentDomain.UnhandledException += delegate => {...};
return true;
}
//Application Lifecycle / State Change Event Handlers... (i.e. OnActivated, WillEnterForeground, etc...)
}
}
Metronome
using System;
using System.IO;
using System.Text;
using MonoTouch.AVFoundation;
using MonoTouch.AudioToolbox;
using MonoTouch.Foundation;
using Dervish.Enums;
using Dervish.EventArgs;
using Dervish.Interfaces;
using Dervish.Midi;
namespace Dervish
{
public class Metronome : IDisposable
{
int _bpm = 120;
NSError _err;
AVAudioPlayer _player;
HighPrecisionTimer _timer;
public HighPrecisionTimer Timer { get { return _timer; }}
public event EventHandler<BeatEventArgs> OnBeat;
public event EventHandler<EventArgs> OnStop;
public Metronome()
{
_timer = new HighPrecisionTimer(_bpm);
_timer.OnPulse += HandlePulse;
//loads sound from base64 file as binary array into memory to reduce HD access
var base64 = File.ReadAllText("click_base64.txt", Encoding.UTF8);
var data = new NSData(base64, NSDataBase64DecodingOptions.IgnoreUnknownCharacters);
_player = AVAudioPlayer.FromData(data, out _err);
if (_err == null)
{
_player.BeginInterruption += delegate {...};
_player.DecoderError += delegate => {...};
_player.EndInterruption += delegate {...};
_player.FinishedPlaying += delegate => {...};
//play once silently to initialize (otherwise there is significant lag on first use)
_player.Volume = 0.0f;
_player.Play();
this.OnBeat += (s, e) =>
{
_player.Play();
};
}
}
public void Start(Status mode)
{
MidiHelper.SendStartMessage();
_player.Volume = 1.0f;
_timer.Start();
}
public void Stop()
{
MidiHelper.SendStopMessage();
OnStop(this, null);
_timer.Stop();
_player.Stop();
}
void HandlePulse (object sender, PulseEventArgs e)
{
MidiHelper.SendClockMessage();
if (e.CurrentPulsePerQuarterNote == 1)
{
OnBeat(this, new BeatEventArgs(BeatType.Down));
}
}
public void Dispose()
{
if (_timer != null) { _timer.Stop(); }
if (_player != null) { _player.Stop(); }
}
}
}
If I can't get this working, I'm dead in the water...