diff --git a/src/AudioToolbox/MusicSequence.cs b/src/AudioToolbox/MusicSequence.cs index 59053c379c9f..d35e1219711d 100644 --- a/src/AudioToolbox/MusicSequence.cs +++ b/src/AudioToolbox/MusicSequence.cs @@ -6,9 +6,6 @@ // // Copyright 2012-2014 Xamarin Inc. // -// MISSING: -// MusicSequenceSetUserCallback -// #if IOS || TVOS @@ -30,6 +27,12 @@ namespace XamCore.AudioToolbox { +#if !COREBUILD + public delegate void MusicSequenceUserCallback (MusicTrack track, double inEventTime, MusicEventUserData inEventData, double inStartSliceBeat, double inEndSliceBeat); + + delegate void MusicSequenceUserCallbackProxy (/* void * */ IntPtr inClientData, /* MusicSequence* */ IntPtr inSequence, /* MusicTrack* */ IntPtr inTrack, /* MusicTimeStamp */ double inEventTime, /* MusicEventUserData* */ IntPtr inEventData, /* MusicTimeStamp */ double inStartSliceBeat, /* MusicTimeStamp */ double inEndSliceBeat); +#endif + // MusicPlayer.h public class MusicSequence : INativeObject #if !COREBUILD @@ -42,6 +45,10 @@ internal MusicSequence (IntPtr handle) { this.handle = handle; } + static Dictionary userCallbackHandles = new Dictionary (); + + static MusicSequenceUserCallbackProxy userCallbackProxy = new MusicSequenceUserCallbackProxy (UserCallbackProxy); + [DllImport (Constants.AudioToolboxLibrary)] extern static /* OSStatus */ MusicPlayerStatus NewMusicSequence (/* MusicSequence* */ out IntPtr outSequence); @@ -73,6 +80,13 @@ public IntPtr Handle { protected virtual void Dispose (bool disposing) { if (handle != IntPtr.Zero){ + + lock (userCallbackHandles) + userCallbackHandles.Remove (handle); + + // Remove native user callback + MusicSequenceSetUserCallback (handle, null, IntPtr.Zero); + DisposeMusicSequence (handle); lock (sequenceMap){ sequenceMap.Remove (handle); @@ -274,6 +288,35 @@ public double GetBeatsForSeconds (double seconds) return beats; return 0; } + + [DllImport (Constants.AudioToolboxLibrary)] + extern static /* OSStatus */ MusicPlayerStatus MusicSequenceSetUserCallback (/* MusicSequence */ IntPtr inSequence, MusicSequenceUserCallbackProxy inCallback, /* void * */ IntPtr inClientData); + + public void SetUserCallback (MusicSequenceUserCallback callback) + { + lock (userCallbackHandles) + userCallbackHandles [handle] = callback; + + MusicSequenceSetUserCallback (handle, userCallbackProxy, IntPtr.Zero); + } + +#if !MONOMAC + [MonoPInvokeCallback (typeof (MusicSequenceUserCallbackProxy))] +#endif + static void UserCallbackProxy (IntPtr inClientData, IntPtr inSequence, IntPtr inTrack, double inEventTime, IntPtr inEventData, double inStartSliceBeat, double inEndSliceBeat) + { + MusicSequenceUserCallback userCallback; + lock (userCallbackHandles) + userCallbackHandles.TryGetValue (inSequence, out userCallback); + + if (userCallback != null) { + var userEventData = new MusicEventUserData (inEventData); + var musicSequence = MusicSequence.Lookup (inSequence); + var musicTrack = new MusicTrack (musicSequence, inTrack, false); + + userCallback (musicTrack, inEventTime, userEventData, inStartSliceBeat, inEndSliceBeat); + } + } [DllImport (Constants.AudioToolboxLibrary)] extern static /* OSStatus */ MusicPlayerStatus MusicSequenceBeatsToBarBeatTime (/* MusicSequence */ IntPtr inSequence, /* MusicTimeStamp */ double inBeats, /* UInt32 */ int inSubbeatDivisor, out CABarBeatTime outBarBeatTime); diff --git a/src/AudioToolbox/MusicTrack.cs b/src/AudioToolbox/MusicTrack.cs index d4dbb5fb744b..abae2a14180a 100644 --- a/src/AudioToolbox/MusicTrack.cs +++ b/src/AudioToolbox/MusicTrack.cs @@ -129,6 +129,20 @@ internal override IntPtr ToUnmanaged () public class MusicEventUserData : MidiRawData { public MusicEventUserData () {} + + internal MusicEventUserData (IntPtr handle) + { + if (handle == IntPtr.Zero) + throw new ArgumentNullException (nameof (handle)); + + int length = Marshal.ReadInt32 (handle); + + var buffer = new byte [length]; + Marshal.Copy (handle + 4, buffer, 0, length); + + len = length; + data = buffer; + } } //