Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Phase] Implement Xcode 16.0 beta 1-6 changes. #21156

Merged
merged 7 commits into from
Sep 12, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions src/AudioToolbox/AudioType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1484,6 +1484,70 @@ public override string ToString ()
}
}

/// <summary>This struct represents the native <see href="https://developer.apple.com/documentation/coreaudiotypes/audiobufferlist">AudioBufferList</see> struct.</summary>
/// <remarks>
/// <para>
/// Typically it's better to use the <see cref="AudioBuffers" /> class to wrap a pointer to a native AudioBufferList,
/// but some audio code needs to minimize memory allocations due to being executed in a realtime thread. In that case,
/// using this struct is better, because it's possible to use it without incurring any memory allocations.
/// </para>
///
/// <para>
/// Note that this struct should never be created in C#, the only valid way to use it is to cast a pointer (<see cref="IntPtr" />)
/// to a pointer of this struct:
/// </para>
///
/// <example>
/// <code lang="csharp lang-csharp"><![CDATA[
/// public unsafe static void Callback (IntPtr audioBufferListPtr) {
/// AudioBufferList* audioBufferList = (AudioBufferList* ) audioBufferListPtr;
/// for (var i = 0; i < audioBufferList->Count; i++) {
/// AudioBuffer* buffer = audioBufferList->GetBuffer (index),
/// // Use the buffer for something
/// }
/// }
/// ]]></code>
/// </example>
/// </remarks>
#if NET
[SupportedOSPlatform ("ios")]
[SupportedOSPlatform ("maccatalyst")]
[SupportedOSPlatform ("macos")]
[SupportedOSPlatform ("tvos")]
#endif
[StructLayout (LayoutKind.Sequential)]
public unsafe struct AudioBufferList {
uint mNumberOfBuffers;

/// <summary>Returns the number of audio buffers in this list.</summary>
public uint Count { get => mNumberOfBuffers; }

/// <summary>Return a pointer to the <see cref="AudioBuffer" /> at the specified index.</summary>
/// <param name="index">The index of the <see cref="AudioBuffer" /> to retrieve.</param>
/// <returns>A pointer to the <see cref="AudioBuffer" /> at the specified index.</returns>
public AudioBuffer* GetBuffer (int index)
{
if (index < 0 || index >= Count)
throw new ArgumentOutOfRangeException (nameof (index));

//
// Decodes
//
// struct AudioBufferList
// {
// UInt32 mNumberBuffers;
// AudioBuffer mBuffers[1]; // this is a variable length array of mNumberBuffers elements
// }
//
fixed (uint* bufferPtr = &mNumberOfBuffers) {
byte* baddress = (byte*) bufferPtr;

var ptr = baddress + IntPtr.Size + index * sizeof (AudioBuffer);
return (AudioBuffer*) ptr;
}
}
}

// CoreAudioClock.h (inside AudioToolbox)
// It was a confusion between CA (CoreAudio) and CA (CoreAnimation)
#if NET
Expand Down
89 changes: 86 additions & 3 deletions src/phase.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using AudioToolbox;
using AVFoundation;
using CoreFoundation;
using Foundation;
Expand Down Expand Up @@ -238,6 +239,14 @@ public enum PhaseSpatialPipelineFlags : ulong {
LateReverb = 1uL << 2,
}

[Flags]
[NoWatch, TV (18, 0), Mac (15, 0), iOS (18, 0), MacCatalyst (18, 0)]
[Native]
[NativeName ("PHASEAutomaticHeadTrackingFlags")]
public enum PhaseAutomaticHeadTrackingFlags : ulong {
None = 0,
Orientation = 1UL << 0,
}

[NoWatch, TV (17, 0), Mac (12, 0), iOS (15, 0), MacCatalyst (15, 0)]
[BaseType (typeof (NSObject), Name = "PHASENumericPair")]
Expand Down Expand Up @@ -707,6 +716,23 @@ interface PhaseRandomNodeDefinition {
nint UniqueSelectionQueueLength { get; set; }
}

[NoWatch, TV (18, 0), Mac (15, 0), iOS (18, 0), MacCatalyst (18, 0)]
[BaseType (typeof (NSObject), Name = "PHASEStreamNode")]
[DisableDefaultCtor]
interface PhaseStreamNode {
[Export ("gainMetaParameter", ArgumentSemantic.Strong), NullAllowed]
PhaseNumberMetaParameter GainMetaParameter { get; }

[Export ("rateMetaParameter", ArgumentSemantic.Strong), NullAllowed]
PhaseNumberMetaParameter RateMetaParameter { get; }

[Export ("mixer", ArgumentSemantic.Strong)]
PhaseMixer Mixer { get; }

[Export ("format", ArgumentSemantic.Strong)]
AVAudioFormat Format { get; }
}

[NoWatch, TV (17, 0), Mac (12, 0), iOS (15, 0), MacCatalyst (15, 0)]
[BaseType (typeof (PhaseGeneratorNodeDefinition), Name = "PHASEPushStreamNodeDefinition")]
[DisableDefaultCtor]
Expand All @@ -726,13 +752,13 @@ interface PhasePushStreamNodeDefinition {
}

[NoWatch, TV (17, 0), Mac (12, 0), iOS (15, 0), MacCatalyst (15, 0)]
[BaseType (typeof (NSObject), Name = "PHASEPushStreamNode")]
[BaseType (typeof (PhaseStreamNode), Name = "PHASEPushStreamNode")]
[DisableDefaultCtor]
interface PhasePushStreamNode {
[NullAllowed, Export ("gainMetaParameter", ArgumentSemantic.Strong)]
[Export ("gainMetaParameter", ArgumentSemantic.Strong), NullAllowed]
PhaseNumberMetaParameter GainMetaParameter { get; }

[NullAllowed, Export ("rateMetaParameter", ArgumentSemantic.Strong)]
[Export ("rateMetaParameter", ArgumentSemantic.Strong), NullAllowed]
PhaseNumberMetaParameter RateMetaParameter { get; }

[Export ("mixer", ArgumentSemantic.Strong)]
Expand Down Expand Up @@ -1131,6 +1157,10 @@ interface PhaseSoundEvent {

[Export ("indefinite")]
bool Indefinite { [Bind ("isIndefinite")] get; }

[TV (18, 0), Mac (15, 0), iOS (18, 0), MacCatalyst (18, 0)]
[Export ("pullStreamNodes", ArgumentSemantic.Copy)]
NSDictionary<NSString, PhasePullStreamNode> PullStreamNodes { get; }
}

[NoWatch, TV (17, 0), Mac (12, 0), iOS (15, 0), MacCatalyst (15, 0)]
Expand Down Expand Up @@ -1200,6 +1230,10 @@ interface PhaseListener {

[Export ("gain")]
double Gain { get; set; }

[TV (18, 0), Mac (15, 0), iOS (18, 0), MacCatalyst (18, 0)]
[Export ("automaticHeadTrackingFlags", ArgumentSemantic.Assign)]
PhaseAutomaticHeadTrackingFlags AutomaticHeadTrackingFlags { get; set; }
}

[NoWatch, TV (17, 0), Mac (12, 0), iOS (15, 0), MacCatalyst (15, 0)]
Expand Down Expand Up @@ -1296,4 +1330,53 @@ interface PhaseSpatialPipeline {
[Export ("entries", ArgumentSemantic.Copy)]
NSDictionary<NSString, PhaseSpatialPipelineEntry> Entries { get; }
}

/// <summary>This is a delegate to provide audio data to a <see cref="PhasePullStreamNode" />.</summary>
/// <param name="isSilence">It's possible to hint to the receiver of the buffer that the returned audio samples are silence. Note that since this is just a hint, the returned audio samples should also be silence.</param>
/// <param name="timeStamp">The HAL time when the sample is to be rendered.</param>
/// <param name="frameCount">The number of sample frames requested.</param>
/// <param name="outputData">
/// <para>The list of audio buffers where to store the returned audio samples.</para>
/// <para>
/// The caller will provide the list of audio buffers, but the callback may replace the
/// <see cref="AudioBuffer.Data" /> pointer (and update the <see cref="AudioBuffer.DataByteSize" /> value)
/// with a pointer to a memory location that the callback owns, and which will be valid until
/// the next render cycle.
/// </para>
/// </param>
/// <returns>0 in case of success, otherwise an OSStatus error code. The audio data will be assumed to be invalid in case of an error.</returns>
public unsafe delegate /* OSStatus */ int PhasePullStreamRenderBlock (
/* BOOL * */ byte* isSilence,
/* const AudioTimeStamp * */ AudioTimeStamp* timeStamp,
/* AVAudioFrameCount */ uint frameCount,
/* AudioBufferList * */ AudioBufferList* outputData);

[NoWatch, TV (18, 0), Mac (15, 0), iOS (18, 0), MacCatalyst (18, 0)]
[BaseType (typeof (PhaseGeneratorNodeDefinition), Name = "PHASEPullStreamNodeDefinition")]
[DisableDefaultCtor]
interface PhasePullStreamNodeDefinition {
[Export ("initWithMixerDefinition:format:identifier:")]
NativeHandle Constructor (PhaseMixerDefinition mixerDefinition, AVAudioFormat format, string identifier);

[DesignatedInitializer]
[Export ("initWithMixerDefinition:format:")]
NativeHandle Constructor (PhaseMixerDefinition mixerDefinition, AVAudioFormat format);

[Export ("format", ArgumentSemantic.Strong)]
AVAudioFormat Format { get; }

[Export ("normalize")]
bool Normalize { get; set; }
}

[NoWatch, TV (18, 0), Mac (15, 0), iOS (18, 0), MacCatalyst (18, 0)]
[BaseType (typeof (PhaseStreamNode), Name = "PHASEPullStreamNode")]
[DisableDefaultCtor]
interface PhasePullStreamNode {
// Apple's header says:
// "Your implementation must be performant and not perform any realtime unsafe operations such as lock mutexes or allocate memory."
// So not offering a strongly typed delegate type, because that would involve memory allocations, just offer the rawest version.
[Export ("renderBlock", ArgumentSemantic.Strong)]
PhasePullStreamRenderBlock RenderBlock { get; set; }
}
}
17 changes: 17 additions & 0 deletions tests/cecil-tests/Documentation.KnownFailures.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16789,6 +16789,8 @@ F:Phase.PhaseAssetError.InvalidEngineInstance
F:Phase.PhaseAssetError.MemoryAllocation
F:Phase.PhaseAssetType.Resident
F:Phase.PhaseAssetType.Streamed
F:Phase.PhaseAutomaticHeadTrackingFlags.None
F:Phase.PhaseAutomaticHeadTrackingFlags.Orientation
F:Phase.PhaseCalibrationMode.AbsoluteSpl
F:Phase.PhaseCalibrationMode.None
F:Phase.PhaseCalibrationMode.RelativeSpl
Expand Down Expand Up @@ -45303,6 +45305,8 @@ M:Phase.PhaseObject.RemoveChild(Phase.PhaseObject)
M:Phase.PhaseObject.RemoveChildren
M:Phase.PhaseOccluder.#ctor(Phase.PhaseEngine,Phase.PhaseShape[])
M:Phase.PhaseOccluder.#ctor(Phase.PhaseEngine)
M:Phase.PhasePullStreamNodeDefinition.#ctor(Phase.PhaseMixerDefinition,AVFoundation.AVAudioFormat,System.String)
M:Phase.PhasePullStreamNodeDefinition.#ctor(Phase.PhaseMixerDefinition,AVFoundation.AVAudioFormat)
M:Phase.PhasePushStreamNode.ScheduleBuffer(AVFoundation.AVAudioPcmBuffer,AVFoundation.AVAudioTime,Phase.PhasePushStreamBufferOptions,Phase.PhasePushStreamCompletionCallbackCondition,System.Action{Phase.PhasePushStreamCompletionCallbackCondition})
M:Phase.PhasePushStreamNode.ScheduleBuffer(AVFoundation.AVAudioPcmBuffer,AVFoundation.AVAudioTime,Phase.PhasePushStreamBufferOptions)
M:Phase.PhasePushStreamNode.ScheduleBuffer(AVFoundation.AVAudioPcmBuffer,Phase.PhasePushStreamCompletionCallbackCondition,System.Action{Phase.PhasePushStreamCompletionCallbackCondition})
Expand Down Expand Up @@ -74633,6 +74637,7 @@ P:Phase.PhaseGroupPresetSetting.Gain
P:Phase.PhaseGroupPresetSetting.GainCurveType
P:Phase.PhaseGroupPresetSetting.Rate
P:Phase.PhaseGroupPresetSetting.RateCurveType
P:Phase.PhaseListener.AutomaticHeadTrackingFlags
P:Phase.PhaseListener.Gain
P:Phase.PhaseMappedMetaParameterDefinition.Envelope
P:Phase.PhaseMappedMetaParameterDefinition.InputMetaParameterDefinition
Expand All @@ -74658,6 +74663,9 @@ P:Phase.PhaseObject.Transform
P:Phase.PhaseObject.Up
P:Phase.PhaseObject.WorldTransform
P:Phase.PhaseOccluder.Shapes
P:Phase.PhasePullStreamNode.RenderBlock
P:Phase.PhasePullStreamNodeDefinition.Format
P:Phase.PhasePullStreamNodeDefinition.Normalize
P:Phase.PhasePushStreamNode.Format
P:Phase.PhasePushStreamNode.GainMetaParameter
P:Phase.PhasePushStreamNode.Mixer
Expand All @@ -74677,6 +74685,7 @@ P:Phase.PhaseSoundEvent.Indefinite
P:Phase.PhaseSoundEvent.MetaParameters
P:Phase.PhaseSoundEvent.Mixers
P:Phase.PhaseSoundEvent.PrepareState
P:Phase.PhaseSoundEvent.PullStreamNodes
P:Phase.PhaseSoundEvent.PushStreamNodes
P:Phase.PhaseSoundEvent.RenderingState
P:Phase.PhaseSoundEventNodeDefinition.Children
Expand All @@ -74690,6 +74699,10 @@ P:Phase.PhaseSpatialPipeline.Entries
P:Phase.PhaseSpatialPipeline.Flags
P:Phase.PhaseSpatialPipelineEntry.SendLevel
P:Phase.PhaseSpatialPipelineEntry.SendLevelMetaParameterDefinition
P:Phase.PhaseStreamNode.Format
P:Phase.PhaseStreamNode.GainMetaParameter
P:Phase.PhaseStreamNode.Mixer
P:Phase.PhaseStreamNode.RateMetaParameter
P:Phase.PhaseSwitchNodeDefinition.SwitchMetaParameterDefinition
P:Photos.IPHLivePhotoFrame.Image
P:Photos.IPHLivePhotoFrame.RenderScale
Expand Down Expand Up @@ -84285,6 +84298,7 @@ T:Phase.PhaseAsset
T:Phase.PhaseAssetError
T:Phase.PhaseAssetRegistry
T:Phase.PhaseAssetType
T:Phase.PhaseAutomaticHeadTrackingFlags
T:Phase.PhaseBlendNodeDefinition
T:Phase.PhaseCalibrationMode
T:Phase.PhaseCardioidDirectivityModelParameters
Expand Down Expand Up @@ -84329,6 +84343,8 @@ T:Phase.PhaseNumericPair
T:Phase.PhaseObject
T:Phase.PhaseOccluder
T:Phase.PhasePlaybackMode
T:Phase.PhasePullStreamNode
T:Phase.PhasePullStreamNodeDefinition
T:Phase.PhasePushStreamBufferOptions
T:Phase.PhasePushStreamCompletionCallbackCondition
T:Phase.PhasePushStreamNode
Expand All @@ -84355,6 +84371,7 @@ T:Phase.PhaseSpatialMixerDefinition
T:Phase.PhaseSpatialPipeline
T:Phase.PhaseSpatialPipelineEntry
T:Phase.PhaseSpatialPipelineFlags
T:Phase.PhaseStreamNode
T:Phase.PhaseStringMetaParameter
T:Phase.PhaseStringMetaParameterDefinition
T:Phase.PhaseSwitchNodeDefinition
Expand Down
63 changes: 63 additions & 0 deletions tests/monotouch-test/AudioToolbox/AudioBufferList.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@

#if !__WATCHOS__
#if NET

using System;
using System.Runtime.InteropServices;

using AudioToolbox;
using Foundation;

using ObjCRuntime;

using NUnit.Framework;

namespace MonoTouchFixtures.AudioToolbox {

[TestFixture]
[Preserve (AllMembers = true)]
public class AudioBufferListTest {
[Test]
public unsafe void Usage ()
{
var buffer = new byte [1024];
fixed (byte* ptr = buffer) {
var list = (AudioBufferList*) ptr;
Assert.AreEqual (0, list->Count, "Count");
Assert.Throws<ArgumentOutOfRangeException> (() => list->GetBuffer (0), "Item 0");
Assert.Throws<ArgumentOutOfRangeException> (() => list->GetBuffer (-1), "Item -1");
Assert.Throws<ArgumentOutOfRangeException> (() => list->GetBuffer (1), "Item 1");

*(int*) ptr = 3;
Assert.AreEqual (3, list->Count, "Count B");
for (var i = 0; i < 3; i++) {
Assert.AreEqual (0, list->GetBuffer (i)->NumberChannels, $"NumberChannels B#{i}");
Assert.AreEqual (0, list->GetBuffer (i)->DataByteSize, $"DataByteSize B#{i}");
Assert.AreEqual ((nint) 0, list->GetBuffer (i)->Data, $"Data B#{i}");

list->GetBuffer (i)->NumberChannels = (i + 1) * 10;
list->GetBuffer (i)->DataByteSize = (i + 1) * 100;
list->GetBuffer (i)->Data = new IntPtr ((i + 1) * 1000);
}
Assert.Throws<ArgumentOutOfRangeException> (() => list->GetBuffer (-1), "Item -1 B");
Assert.Throws<ArgumentOutOfRangeException> (() => list->GetBuffer (3), "Item 3 B");

int* iptr = (int*) ptr;
Assert.AreEqual (10, iptr [2 + 0 * 4], "10"); // NumberChannels
Assert.AreEqual (100, iptr [2 + 0 * 4 + 1], "20"); // DataByteSize
Assert.AreEqual (20, iptr [2 + 1 * 4], "20"); // NumberChannels
Assert.AreEqual (200, iptr [2 + 1 * 4 + 1], "40"); // DataByteSize
Assert.AreEqual (30, iptr [2 + 2 * 4], "30"); // NumberChannels
Assert.AreEqual (300, iptr [2 + 2 * 4 + 1], "60"); // DataByteSize

nint* nptr = (nint*) ptr;
Assert.AreEqual ((nint) 1000, nptr [1 + 0 * 2 + 1], "1000"); // Data
Assert.AreEqual ((nint) 2000, nptr [1 + 1 * 2 + 1], "2000"); // Data
Assert.AreEqual ((nint) 3000, nptr [1 + 2 * 2 + 1], "3000"); // Data
}
}
}
}

#endif // NET
#endif // !__WATCHOS__
19 changes: 0 additions & 19 deletions tests/xtro-sharpie/api-annotations-dotnet/MacCatalyst-PHASE.todo

This file was deleted.

19 changes: 0 additions & 19 deletions tests/xtro-sharpie/api-annotations-dotnet/iOS-PHASE.todo

This file was deleted.

Loading
Loading