Skip to content

Commit

Permalink
[AudioToolbox] Make P/Invokes in MusicPlayer.cs have blittable signat…
Browse files Browse the repository at this point in the history
…ures.

Also fix the signature for the Dispose method - it has to override the base
implementation, not provide a new implementation.

Contributes towards xamarin#15684.
  • Loading branch information
rolfbjarne committed Dec 21, 2023
1 parent 51aaac3 commit ce1ccf0
Show file tree
Hide file tree
Showing 3 changed files with 160 additions and 28 deletions.
78 changes: 57 additions & 21 deletions src/AudioToolbox/MusicPlayer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#if !WATCH

using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;

Expand Down Expand Up @@ -86,7 +87,7 @@ public enum MusicSequenceFileFlags {
// MusicPlayer.h
public class MusicPlayer : DisposableObject {
[DllImport (Constants.AudioToolboxLibrary)]
extern static /* OSStatus */ MusicPlayerStatus NewMusicPlayer (/* MusicPlayer* */ out IntPtr outPlayer);
unsafe extern static /* OSStatus */ MusicPlayerStatus NewMusicPlayer (/* MusicPlayer* */ IntPtr* outPlayer);

[DllImport (Constants.AudioToolboxLibrary)]
extern static /* OSStatus */ MusicPlayerStatus DisposeMusicPlayer (/* MusicPlayer */ IntPtr inPlayer);
Expand All @@ -97,17 +98,18 @@ public class MusicPlayer : DisposableObject {
{
}

new protected virtual void Dispose (bool disposing)
protected override void Dispose (bool disposing)
{
currentSequence = null;
if (Owns && Handle != IntPtr.Zero)
DisposeMusicPlayer (Handle);
base.Dispose (disposing);
}

static IntPtr Create ()
unsafe static IntPtr Create ()
{
var result = NewMusicPlayer (out var handle);
IntPtr handle;
var result = NewMusicPlayer (&handle);
if (result == MusicPlayerStatus.Success)
return handle;
throw new Exception ("Unable to create MusicPlayer: " + result);
Expand All @@ -120,7 +122,10 @@ public MusicPlayer ()

static public MusicPlayer? Create (out MusicPlayerStatus OSstatus)
{
OSstatus = NewMusicPlayer (out var handle);
IntPtr handle;
unsafe {
OSstatus = NewMusicPlayer (&handle);
}
if (OSstatus == 0)
return new MusicPlayer (handle, true);
return null;
Expand All @@ -131,21 +136,37 @@ public MusicPlayer ()
// note: MusicTimeStamp -> Float64

[DllImport (Constants.AudioToolboxLibrary)]
extern static /* OSStatus */ MusicPlayerStatus MusicPlayerGetTime (/* MusicPlayer */ IntPtr inPlayer, /* MusicTimeStamp* */ out double outTime);
unsafe extern static /* OSStatus */ MusicPlayerStatus MusicPlayerGetTime (/* MusicPlayer */ IntPtr inPlayer, /* MusicTimeStamp* */ double* outTime);

[DllImport (Constants.AudioToolboxLibrary)]
extern static /* OSStatus */ MusicPlayerStatus MusicPlayerSetTime (/* MusicPlayer */ IntPtr inPlayer, /* MusicTimeStamp* */ double inTime);

public double Time {
get {
MusicPlayerGetTime (Handle, out var time);
double time;
unsafe {
MusicPlayerGetTime (Handle, &time);
}
return time;
}
set {
MusicPlayerSetTime (Handle, value);
}
}

public MusicPlayerStatus GetTime (out double time)
{
time = 0;
unsafe {
return MusicPlayerGetTime (Handle, (double *) Unsafe.AsPointer<double> (ref time));
}
}

public MusicPlayerStatus SetTime (double time)
{
return MusicPlayerSetTime (Handle, time);
}

[DllImport (Constants.AudioToolboxLibrary)]
extern static /* OSStatus */ MusicPlayerStatus MusicPlayerPreroll (/* MusicPlayer */ IntPtr inPlayer);

Expand All @@ -171,24 +192,30 @@ public MusicPlayerStatus Stop ()
}

[DllImport (Constants.AudioToolboxLibrary)]
extern static /* OSStatus */ MusicPlayerStatus MusicPlayerIsPlaying (/* MusicPlayer */ IntPtr inPlayer, /* Boolean* */ [MarshalAs (UnmanagedType.I1)] out bool outIsPlaying);
unsafe extern static /* OSStatus */ MusicPlayerStatus MusicPlayerIsPlaying (/* MusicPlayer */ IntPtr inPlayer, /* Boolean* */ byte* outIsPlaying);

public bool IsPlaying {
get {
MusicPlayerIsPlaying (Handle, out var res);
return res;
byte res;
unsafe {
MusicPlayerIsPlaying (Handle, &res);
}
return res != 0;
}
}

[DllImport (Constants.AudioToolboxLibrary)]
extern static /* OSStatus */ MusicPlayerStatus MusicPlayerSetPlayRateScalar (/* MusicPlayer */ IntPtr inPlayer, /* Float64 */ double inScaleRate);

[DllImport (Constants.AudioToolboxLibrary)]
extern static /* OSStatus */ MusicPlayerStatus MusicPlayerGetPlayRateScalar (/* MusicPlayer */ IntPtr inPlayer, /* Float64* */ out double outScaleRate);
unsafe extern static /* OSStatus */ MusicPlayerStatus MusicPlayerGetPlayRateScalar (/* MusicPlayer */ IntPtr inPlayer, /* Float64* */ double* outScaleRate);

public double PlayRateScalar {
get {
MusicPlayerGetPlayRateScalar (Handle, out var rate);
double rate;
unsafe {
MusicPlayerGetPlayRateScalar (Handle, &rate);
}
return rate;
}
set {
Expand All @@ -197,34 +224,43 @@ public double PlayRateScalar {
}

[DllImport (Constants.AudioToolboxLibrary)]
extern static /* OSStatus */ MusicPlayerStatus MusicPlayerGetHostTimeForBeats (/* MusicPlayer */ IntPtr inPlayer, /* MusicTimeStamp */ double inBeats, /* UInt64* */ out long outHostTime);
unsafe extern static /* OSStatus */ MusicPlayerStatus MusicPlayerGetHostTimeForBeats (/* MusicPlayer */ IntPtr inPlayer, /* MusicTimeStamp */ double inBeats, /* UInt64* */ long* outHostTime);

public MusicPlayerStatus GetHostTimeForBeats (double beats, out long hostTime)
{
return MusicPlayerGetHostTimeForBeats (Handle, beats, out hostTime);
hostTime = 0;
unsafe {
return MusicPlayerGetHostTimeForBeats (Handle, beats, (long *) Unsafe.AsPointer<long> (ref hostTime));
}
}

[DllImport (Constants.AudioToolboxLibrary)]
extern static /* OSStatus */ MusicPlayerStatus MusicPlayerGetBeatsForHostTime (/* MusicPlayer */ IntPtr inPlayer, /* UInt64 */ long inHostTime, /* MusicTimeStamp* */ out double outBeats);
unsafe extern static /* OSStatus */ MusicPlayerStatus MusicPlayerGetBeatsForHostTime (/* MusicPlayer */ IntPtr inPlayer, /* UInt64 */ long inHostTime, /* MusicTimeStamp* */ double* outBeats);

public MusicPlayerStatus GetBeatsForHostTime (long hostTime, out double beats)
{
return MusicPlayerGetBeatsForHostTime (Handle, hostTime, out beats);
beats = 0;
unsafe {
return MusicPlayerGetBeatsForHostTime (Handle, hostTime, (double *) Unsafe.AsPointer<double> (ref beats));
}
}


[DllImport (Constants.AudioToolboxLibrary)]
extern static /* OSStatus */ MusicPlayerStatus MusicPlayerGetSequence (/* MusicPlayer */ IntPtr inPlayer, /* MusicSequence* */ out IntPtr outSequence);
unsafe extern static /* OSStatus */ MusicPlayerStatus MusicPlayerGetSequence (/* MusicPlayer */ IntPtr inPlayer, /* MusicSequence* */ IntPtr* outSequence);

[DllImport (Constants.AudioToolboxLibrary)]
extern static /* OSStatus */ MusicPlayerStatus MusicPlayerSetSequence (/* MusicPlayer */ IntPtr inPlayer, IntPtr inSequence);

public MusicSequence? MusicSequence {
get {
if (MusicPlayerGetSequence (Handle, out var seqHandle) == MusicPlayerStatus.Success)
return MusicSequence.Lookup (seqHandle);
else
return null;
IntPtr seqHandle;
unsafe {
if (MusicPlayerGetSequence (Handle, &seqHandle) == MusicPlayerStatus.Success)
return MusicSequence.Lookup (seqHandle);
}

return null;
}
set {
currentSequence = value;
Expand Down
7 changes: 0 additions & 7 deletions tests/cecil-tests/BlittablePInvokes.KnownFailures.cs
Original file line number Diff line number Diff line change
Expand Up @@ -79,13 +79,6 @@ public partial class BlittablePInvokes {
"AudioToolbox.AudioServicesError AudioToolbox.AudioServices::AudioServicesGetProperty(AudioToolbox.AudioServicesPropertyKey,System.UInt32,System.UInt32&,System.UInt32&,System.UInt32&)",
"AudioToolbox.AudioServicesError AudioToolbox.AudioServices::AudioServicesSetProperty(AudioToolbox.AudioServicesPropertyKey,System.UInt32,System.UInt32&,System.UInt32,System.UInt32&)",
"AudioToolbox.AudioServicesError AudioToolbox.SystemSound::AudioServicesCreateSystemSoundID(System.IntPtr,System.UInt32&)",
"AudioToolbox.MusicPlayerStatus AudioToolbox.MusicPlayer::MusicPlayerGetBeatsForHostTime(System.IntPtr,System.Int64,System.Double&)",
"AudioToolbox.MusicPlayerStatus AudioToolbox.MusicPlayer::MusicPlayerGetHostTimeForBeats(System.IntPtr,System.Double,System.Int64&)",
"AudioToolbox.MusicPlayerStatus AudioToolbox.MusicPlayer::MusicPlayerGetPlayRateScalar(System.IntPtr,System.Double&)",
"AudioToolbox.MusicPlayerStatus AudioToolbox.MusicPlayer::MusicPlayerGetSequence(System.IntPtr,System.IntPtr&)",
"AudioToolbox.MusicPlayerStatus AudioToolbox.MusicPlayer::MusicPlayerGetTime(System.IntPtr,System.Double&)",
"AudioToolbox.MusicPlayerStatus AudioToolbox.MusicPlayer::MusicPlayerIsPlaying(System.IntPtr,System.Boolean&)",
"AudioToolbox.MusicPlayerStatus AudioToolbox.MusicPlayer::NewMusicPlayer(System.IntPtr&)",
"AudioToolbox.MusicPlayerStatus AudioToolbox.MusicSequence::MusicSequenceBarBeatTimeToBeats(System.IntPtr,AudioToolbox.CABarBeatTime,System.Double&)",
"AudioToolbox.MusicPlayerStatus AudioToolbox.MusicSequence::MusicSequenceBeatsToBarBeatTime(System.IntPtr,System.Double,System.Int32,AudioToolbox.CABarBeatTime&)",
"AudioToolbox.MusicPlayerStatus AudioToolbox.MusicSequence::MusicSequenceFileCreateData(System.IntPtr,AudioToolbox.MusicSequenceFileTypeID,AudioToolbox.MusicSequenceFileFlags,System.UInt16,System.IntPtr&)",
Expand Down
103 changes: 103 additions & 0 deletions tests/monotouch-test/AudioToolbox/MusicPlayer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
//
// MusicPlayer unit Tests
//
// Authors:
// Rolf Bjarne Kvinge <[email protected]>
//
// Copyright 2023 Microsoft Corp. All rights reserved.
//

#if !__WATCHOS__

using System;

using AudioToolbox;
using Foundation;
using ObjCRuntime;

using NUnit.Framework;

namespace MonoTouchFixtures.AudioToolbox {

[TestFixture]
[Preserve (AllMembers = true)]
public class MusicPlayerTest {

[Test]
public void Defaults ()
{
using (var player = new MusicPlayer ()) {
Assert.IsFalse (player.IsPlaying, "IsPlaying");
Assert.AreEqual (0, player.Time, "Time");
Assert.AreEqual (1, player.PlayRateScalar, "PlayRateScalar");
Assert.AreEqual (MusicPlayerStatus.InvalidPlayerState, player.GetHostTimeForBeats (0, out var hosttime), "GetHostTimeForBeats");
Assert.AreEqual (0, hosttime, "GetHostTimeForBeats - rv");
Assert.AreEqual (MusicPlayerStatus.InvalidPlayerState, player.GetBeatsForHostTime (0, out var beats), "GetBeatsForHostTime");
Assert.AreEqual (0, beats, "GetBeatsForHostTime - rv");
Assert.IsNull (player.MusicSequence, "MusicSequence");
}
}

[Test]
public void MusicSequenceTest ()
{
using (var player = new MusicPlayer ()) {
using (var ms = new MusicSequence ()) {
Assert.IsNull (player.MusicSequence, "MusicSequence A");
player.MusicSequence = null;
Assert.IsNull (player.MusicSequence, "MusicSequence B");
player.MusicSequence = ms;
Assert.AreSame (ms, player.MusicSequence, "MusicSequence C");
player.MusicSequence = null;
Assert.IsNull (player.MusicSequence, "MusicSequence D");
}
}
}

[Test]
public void PlayRateScalarTest ()
{
using (var player = new MusicPlayer ()) {
Assert.AreEqual (1, player.PlayRateScalar, "PlayRateScalar A");
player.PlayRateScalar = 2;
Assert.AreEqual (2, player.PlayRateScalar, "PlayRateScalar B");
}
}

[Test]
public void TimeTest ()
{
using (var player = new MusicPlayer ()) {
Assert.AreEqual (0, player.Time, "Time A");
player.Time = 1;
Assert.AreEqual (0, player.Time, "Time B");
Assert.AreEqual (MusicPlayerStatus.Success, player.GetTime (out var time), "GetTime A");
Assert.AreEqual (0, time, "GetTime B");
Assert.AreEqual (MusicPlayerStatus.Success, player.SetTime (1), "SetTime A");
Assert.AreEqual (MusicPlayerStatus.Success, player.GetTime (out time), "GetTime C");
Assert.AreEqual (0, time, "GetTime D");
}
}

[Test]
public void CreateTest ()
{
using var player = MusicPlayer.Create (out var status);
Assert.NotNull (player, "Got a player");
Assert.AreEqual (MusicPlayerStatus.Success, status, "Status");
}

[Test]
public void StartStopPreroll ()
{
using var player = MusicPlayer.Create (out var status);
Assert.NotNull (player, "Got a player");
Assert.AreEqual (MusicPlayerStatus.Success, status, "Status");
Assert.AreEqual (MusicPlayerStatus.NoSequence, player.Preroll (), "Preroll");
Assert.AreEqual (MusicPlayerStatus.NoSequence, player.Start (), "Start");
Assert.AreEqual (MusicPlayerStatus.NoSequence, player.Stop (), "Stop");
}
}
}

#endif // !__WATCHOS__

0 comments on commit ce1ccf0

Please sign in to comment.