From 7129ea059f6778264a5bd61103d9699f4506f64d Mon Sep 17 00:00:00 2001 From: Rolf Bjarne Kvinge Date: Thu, 4 Sep 2025 08:09:46 +0200 Subject: [PATCH 1/2] [AudioToolbox] Improve AudioFile API a little bit. * Add numerous overloads that returns the error code, obsolete other overloads. * Some code updates as well. * Update a lot of the xml docs. * Update tests to: * Verify the status code. * Use the temporary directory instead of the Documents directory. * Clean up after themselves. --- docs/api/AudioToolbox/AudioFile.xml | 14 - docs/api/AudioToolbox/AudioFileMarkerList.xml | 14 - docs/api/AudioToolbox/AudioFileRegionList.xml | 14 - docs/api/AudioToolbox/AudioSource.xml | 14 - src/AudioToolbox/AudioFile.cs | 1260 ++++++++--------- .../AudioToolbox/AudioConverterTest.cs | 46 +- 6 files changed, 609 insertions(+), 753 deletions(-) delete mode 100644 docs/api/AudioToolbox/AudioFile.xml delete mode 100644 docs/api/AudioToolbox/AudioFileMarkerList.xml delete mode 100644 docs/api/AudioToolbox/AudioFileRegionList.xml delete mode 100644 docs/api/AudioToolbox/AudioSource.xml diff --git a/docs/api/AudioToolbox/AudioFile.xml b/docs/api/AudioToolbox/AudioFile.xml deleted file mode 100644 index 728130b96a30..000000000000 --- a/docs/api/AudioToolbox/AudioFile.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - If set to , the method is invoked directly and will dispose managed and unmanaged resources; If set to the method is being called by the garbage collector finalizer and should only release unmanaged resources. - - Releases the resources used by the AudioFile object. - - This Dispose method releases the resources used by the AudioFile class. - This method is called by both the Dispose() method and the object finalizer (Finalize). When invoked by the Dispose method, the parameter disposing is set to and any managed object references that this object holds are also disposed or released; when invoked by the object finalizer, on the finalizer thread the value is set to . - Calling the Dispose method when the application is finished using the AudioFile ensures that all external resources used by this managed object are released as soon as possible. Once developers have invoked the Dispose method, the object is no longer useful and developers should no longer make any calls to it. - For more information on how to override this method and on the Dispose/IDisposable pattern, read the ``Implementing a Dispose Method'' document at https://msdn.microsoft.com/en-us/library/fs2xkftw.aspx - - - \ No newline at end of file diff --git a/docs/api/AudioToolbox/AudioFileMarkerList.xml b/docs/api/AudioToolbox/AudioFileMarkerList.xml deleted file mode 100644 index a1125a7e876c..000000000000 --- a/docs/api/AudioToolbox/AudioFileMarkerList.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - If set to , the method is invoked directly and will dispose managed and unmanaged resources; If set to the method is being called by the garbage collector finalizer and should only release unmanaged resources. - - Releases the resources used by the AudioFileMarkerList object. - - This Dispose method releases the resources used by the AudioFileMarkerList class. - This method is called by both the Dispose() method and the object finalizer (Finalize). When invoked by the Dispose method, the parameter disposing is set to and any managed object references that this object holds are also disposed or released; when invoked by the object finalizer, on the finalizer thread the value is set to . - Calling the Dispose method when the application is finished using the AudioFileMarkerList ensures that all external resources used by this managed object are released as soon as possible. Once developers have invoked the Dispose method, the object is no longer useful and developers should no longer make any calls to it. - For more information on how to override this method and on the Dispose/IDisposable pattern, read the ``Implementing a Dispose Method'' document at https://msdn.microsoft.com/en-us/library/fs2xkftw.aspx - - - \ No newline at end of file diff --git a/docs/api/AudioToolbox/AudioFileRegionList.xml b/docs/api/AudioToolbox/AudioFileRegionList.xml deleted file mode 100644 index dcffb6760958..000000000000 --- a/docs/api/AudioToolbox/AudioFileRegionList.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - If set to , the method is invoked directly and will dispose managed and unmanaged resources; If set to the method is being called by the garbage collector finalizer and should only release unmanaged resources. - - Releases the resources used by the AudioFileRegionList object. - - This Dispose method releases the resources used by the AudioFileRegionList class. - This method is called by both the Dispose() method and the object finalizer (Finalize). When invoked by the Dispose method, the parameter disposing is set to and any managed object references that this object holds are also disposed or released; when invoked by the object finalizer, on the finalizer thread the value is set to . - Calling the Dispose method when the application is finished using the AudioFileRegionList ensures that all external resources used by this managed object are released as soon as possible. Once developers have invoked the Dispose method, the object is no longer useful and developers should no longer make any calls to it. - For more information on how to override this method and on the Dispose/IDisposable pattern, read the ``Implementing a Dispose Method'' document at https://msdn.microsoft.com/en-us/library/fs2xkftw.aspx - - - \ No newline at end of file diff --git a/docs/api/AudioToolbox/AudioSource.xml b/docs/api/AudioToolbox/AudioSource.xml deleted file mode 100644 index e17d8361a563..000000000000 --- a/docs/api/AudioToolbox/AudioSource.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - If set to , the method is invoked directly and will dispose managed and unmanaged resources; If set to the method is being called by the garbage collector finalizer and should only release unmanaged resources. - - Releases the resources used by the AudioSource object. - - This Dispose method releases the resources used by the AudioSource class. - This method is called by both the Dispose() method and the object finalizer (Finalize). When invoked by the Dispose method, the parameter disposing is set to and any managed object references that this object holds are also disposed or released; when invoked by the object finalizer, on the finalizer thread the value is set to . - Calling the Dispose method when the application is finished using the AudioSource ensures that all external resources used by this managed object are released as soon as possible. Once developers have invoked the Dispose method, the object is no longer useful and developers should no longer make any calls to it. - For more information on how to override this method and on the Dispose/IDisposable pattern, read the ``Implementing a Dispose Method'' document at https://msdn.microsoft.com/en-us/library/fs2xkftw.aspx - - - \ No newline at end of file diff --git a/src/AudioToolbox/AudioFile.cs b/src/AudioToolbox/AudioFile.cs index 60cc6e94338a..64cc6a64bd12 100644 --- a/src/AudioToolbox/AudioFile.cs +++ b/src/AudioToolbox/AudioFile.cs @@ -33,6 +33,7 @@ using System; using System.IO; using System.Collections.Generic; +using System.ComponentModel; using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -45,8 +46,7 @@ namespace AudioToolbox { - /// Known audio file types. Used to specify the kind of audio file to create, or as a hint to the audio parser about the contents of the file. - /// To be added. + /// Known audio file types. Used to specify the kind of audio file to create, or as a hint to the audio parser about the contents of the file. public enum AudioFileType { // UInt32 AudioFileTypeID /// Audio Interchange File Format. AIFF = 0x41494646, // AIFF @@ -101,11 +101,9 @@ public enum AudioFileType { // UInt32 AudioFileTypeID LatmInLoas = 0x6c6f6173, // loas } - /// The error codes returned by . - /// - /// + /// The error codes returned by . public enum AudioFileError {// Implictly cast to OSType in AudioFile.h - /// To be added. + /// The operation was successful. Success = 0, // noErr /// An unspecified error has occurred. Unspecified = 0x7768743f, // wht? @@ -127,9 +125,11 @@ public enum AudioFileError {// Implictly cast to OSType in AudioFile.h DoesNotAllow64BitDataSize = 0x6f66663f, // off? /// A packet offset is not valid. InvalidPacketOffset = 0x70636b3f, // pck? + /// A packet dependency is not valid. + InvalidPacketDependencyError = 0x6465703f, // dep? /// The file is invalid. InvalidFile = 0x6474613f, // dta? - /// To be added. + /// The operation is not supported. OperationNotSupported = 0x6F703F3F, // op?? /// The file is not opened. FileNotOpen = -38, @@ -141,30 +141,35 @@ public enum AudioFileError {// Implictly cast to OSType in AudioFile.h FilePosition = -40, } - /// An enumeration whose values specify the permissions argument when opening an . - /// To be added. + /// An enumeration whose values specify the permissions argument when opening an . [Flags] public enum AudioFilePermission { - /// To be added. + /// The file is opened for reading. Read = 0x01, - /// To be added. + /// The file is opened for writing. Write = 0x02, - /// To be added. + /// The file is opened for both reading and writing. ReadWrite = 0x03, } - /// An enumeration whose values to select creation options for . - /// To be added. + /// An enumeration whose values to select creation options for . [Flags] public enum AudioFileFlags { // UInt32 in AudioFileCreateWithURL() - /// To be added. +#if !XAMCORE_5_0 + /// If this flag is set, the existing file will be erased when creating an . + [EditorBrowsable (EditorBrowsableState.Never)] + [Obsolete ("Use 'EraseFile' instead.")] EraseFlags = 1, +#endif // !XAMCORE_5_0 + /// If this flag is set, the existing file will be erased when creating an . + EraseFile = 1, /// If this flag is set, audio data will be written without page alignment. This will make the data more compact but possibly slow readout. DontPageAlignAudioData = 2, } - /// An enumeration whose values represent information about a . See the and methods. - /// To be added. + /// An enumeration whose values represent information about a . + /// + /// public enum AudioFileProperty { // typedef UInt32 AudioFilePropertyID /// To be added. FileFormat = 0x66666d74, @@ -233,7 +238,6 @@ public enum AudioFileProperty { // typedef UInt32 AudioFilePropertyID } /// An enumeration whose values specify an audio-loop's direction. - /// To be added. public enum AudioFileLoopDirection { // Unused? /// To be added. NoLooping = 0, @@ -246,7 +250,6 @@ public enum AudioFileLoopDirection { // Unused? } /// An enumeration whose values specify different types of chunks appropriate to audio files. - /// To be added. public enum AudioFileChunkType : uint // CoreAudio.framework - CoreAudioTypes.h - "four char code IDs" { /// To be added. @@ -311,7 +314,6 @@ enum BytePacketTranslationFlags : uint // Stored in UInt32 in AudioBytePacketTr } /// A struct that encapsulates a Society of Motion Picture and Television Engineers time. - /// To be added. [SupportedOSPlatform ("ios")] [SupportedOSPlatform ("maccatalyst")] [SupportedOSPlatform ("macos")] @@ -319,24 +321,18 @@ enum BytePacketTranslationFlags : uint // Stored in UInt32 in AudioBytePacketTr [StructLayout (LayoutKind.Sequential)] public struct AudioFileSmpteTime { // AudioFile_SMPTE_Time /// To be added. - /// To be added. public sbyte Hours; /// To be added. - /// To be added. public byte Minutes; /// To be added. - /// To be added. public byte Seconds; /// To be added. - /// To be added. public byte Frames; /// To be added. - /// To be added. public uint SubFrameSampleOffset; } /// A class that represents a specific named position within an audio file. - /// To be added. [SupportedOSPlatform ("ios")] [SupportedOSPlatform ("maccatalyst")] [SupportedOSPlatform ("macos")] @@ -344,28 +340,20 @@ public struct AudioFileSmpteTime { // AudioFile_SMPTE_Time [StructLayout (LayoutKind.Sequential)] public struct AudioFileMarker { /// To be added. - /// To be added. public double FramePosition; internal IntPtr Name_cfstringref; /// To be added. - /// To be added. public int MarkerID; /// To be added. - /// To be added. public AudioFileSmpteTime SmpteTime; /// To be added. - /// To be added. public AudioFileMarkerType Type; /// To be added. - /// To be added. public ushort Reserved; /// To be added. - /// To be added. public ushort Channel; /// To be added. - /// To be added. - /// To be added. public string? Name { get { return CFString.FromHandle (Name_cfstringref); @@ -420,7 +408,6 @@ public bool IsIndependentlyDecodable { } /// An enumeration whose values specify the property. - /// To be added. public enum AudioFileMarkerType : uint // UInt32 in AudioFileMarkerType - AudioFile.h { /// To be added. @@ -472,8 +459,7 @@ public enum AudioFileMarkerType : uint // UInt32 in AudioFileMarkerType - AudioF CAFKeySignature = 0x6b736967, // 'ksig' } - /// A collection of s. - /// To be added. + /// A list of objects. [SupportedOSPlatform ("ios")] [SupportedOSPlatform ("maccatalyst")] [SupportedOSPlatform ("macos")] @@ -482,10 +468,9 @@ public class AudioFileMarkerList : IDisposable { IntPtr ptr; readonly bool owns; - /// To be added. - /// To be added. - /// To be added. - /// To be added. + /// Create a new instance. + /// The pointer to the native value. + /// Whether the native pointer should be freed when this managed instance is disposed. public AudioFileMarkerList (IntPtr ptr, bool owns) { this.ptr = ptr; @@ -497,24 +482,23 @@ public AudioFileMarkerList (IntPtr ptr, bool owns) Dispose (false); } - /// To be added. - /// To be added. - /// To be added. + /// Get the for this list. public SmpteTimeType SmpteTimeType { get { return (SmpteTimeType) Marshal.ReadInt32 (ptr); } } - /// To be added. - /// To be added. - /// To be added. + /// Get the number of elements in the list. public uint Count { get { return (uint) Marshal.ReadInt32 (ptr, 4); } } + /// Get the element at the specified 0-based index. + /// The 0-based index to return. + /// The element at the specified 0-based index. public AudioFileMarker this [int index] { get { if (index >= Count || index < 0) @@ -537,17 +521,14 @@ public AudioFileMarker this [int index] { } } - /// Releases the resources used by the AudioFileMarkerList object. - /// - /// The Dispose method releases the resources used by the AudioFileMarkerList class. - /// Calling the Dispose method when the application is finished using the AudioFileMarkerList ensures that all external resources used by this managed object are released as soon as possible. Once developers have invoked the Dispose method, the object is no longer useful and developers should no longer make any calls to it. For more information on releasing resources see ``Cleaning up Unmananaged Resources'' at https://msdn.microsoft.com/en-us/library/498928w2.aspx - /// + /// Releases the resources used by the object. public void Dispose () { Dispose (true); } - /// + /// Releases the resources used by the object. + /// If set to , the method is invoked directly and will dispose managed and unmanaged resources; If set to the method is being called by the garbage collector finalizer and should only release unmanaged resources. protected virtual void Dispose (bool disposing) { if (!owns || ptr == IntPtr.Zero) @@ -564,26 +545,22 @@ protected virtual void Dispose (bool disposing) } /// Represents the number of valid frames in a file and where they begin or end. - /// Not all audio file data formats guarantee that their contents are 100% valid; some have priming or remainder frames. This class can be used with such data formats to identify the valid frames in a file. + /// Not all audio file data formats guarantee that their contents are 100% valid; some have priming or remainder frames. This class can be used with such data formats to identify the valid frames in a file. [SupportedOSPlatform ("ios")] [SupportedOSPlatform ("maccatalyst")] [SupportedOSPlatform ("macos")] [SupportedOSPlatform ("tvos")] [StructLayout (LayoutKind.Sequential)] public struct AudioFilePacketTableInfo { - /// To be added. - /// To be added. + /// The number of valid frames in the file. public long ValidFrames; - /// To be added. - /// To be added. + /// The number of priming frames (invalid frames at the beginning) in the file. public int PrimingFrames; - /// To be added. - /// To be added. + /// The number of remainder frames (invalid frames at the end) in the file. public int RemainderFrames; } /// Represents a named region within an audio file. - /// To be added. [SupportedOSPlatform ("ios")] [SupportedOSPlatform ("maccatalyst")] [SupportedOSPlatform ("macos")] @@ -603,26 +580,21 @@ public struct AudioFileRegion { // AudioFileMarker mMarkers[1]; // this is a variable length array of mNumberMarkers elements // } - /// To be added. - /// To be added. - /// To be added. + /// Create a new instance, wrapping a native pointer. + /// The native pointer to wrap. public AudioFileRegion (IntPtr ptr) { this.ptr = ptr; } - /// To be added. - /// To be added. - /// To be added. + /// The region identifier for this region. public uint RegionID { get { return (uint) Marshal.ReadInt32 (ptr); } } - /// To be added. - /// To be added. - /// To be added. + /// The name for this region. public string? Name { get { return CFString.FromHandle (NameWeak); @@ -635,24 +607,23 @@ internal IntPtr NameWeak { } } - /// To be added. - /// To be added. - /// To be added. + /// The flags for this region. public unsafe AudioFileRegionFlags Flags { get { return (AudioFileRegionFlags) Marshal.ReadInt32 (ptr, sizeof (uint) + sizeof (IntPtr)); } } - /// To be added. - /// To be added. - /// To be added. + /// The number of elements in this region. public unsafe int Count { get { return Marshal.ReadInt32 (ptr, 2 * sizeof (uint) + sizeof (IntPtr)); } } + /// Get the element at the specified 0-based index. + /// The 0-based index to return. + /// The element at the specified 0-based index. public AudioFileMarker this [int index] { get { if (index >= Count || index < 0) @@ -672,8 +643,7 @@ internal unsafe int TotalSize { } } - /// A flagging enumeration whose values are used in the property. - /// To be added. + /// A flagging enumeration whose values are used in the property. [Flags] public enum AudioFileRegionFlags : uint // UInt32 in AudioFileRegion { @@ -685,8 +655,7 @@ public enum AudioFileRegionFlags : uint // UInt32 in AudioFileRegion PlayBackward = 4, } - /// A list of s. - /// To be added. + /// A list of values. [SupportedOSPlatform ("ios")] [SupportedOSPlatform ("maccatalyst")] [SupportedOSPlatform ("macos")] @@ -695,10 +664,9 @@ public class AudioFileRegionList : IDisposable { IntPtr ptr; readonly bool owns; - /// To be added. - /// To be added. - /// To be added. - /// To be added. + /// Create a new instance. + /// The pointer to the native value. + /// Whether the native pointer should be freed when this managed instance is disposed. public AudioFileRegionList (IntPtr ptr, bool owns) { this.ptr = ptr; @@ -710,24 +678,23 @@ public AudioFileRegionList (IntPtr ptr, bool owns) Dispose (false); } - /// To be added. - /// To be added. - /// To be added. + /// Get the for this list. public SmpteTimeType SmpteTimeType { get { return (SmpteTimeType) Marshal.ReadInt32 (ptr); } } - /// To be added. - /// To be added. - /// To be added. + /// Get the number of elements in the list. public uint Count { get { return (uint) Marshal.ReadInt32 (ptr, sizeof (uint)); } } + /// Get the element at the specified 0-based index. + /// The 0-based index to return. + /// The element at the specified 0-based index. public AudioFileRegion this [int index] { get { if (index >= Count || index < 0) @@ -755,17 +722,14 @@ public AudioFileRegion this [int index] { } } - /// Releases the resources used by the AudioFileRegionList object. - /// - /// The Dispose method releases the resources used by the AudioFileRegionList class. - /// Calling the Dispose method when the application is finished using the AudioFileRegionList ensures that all external resources used by this managed object are released as soon as possible. Once developers have invoked the Dispose method, the object is no longer useful and developers should no longer make any calls to it. For more information on releasing resources see ``Cleaning up Unmananaged Resources'' at https://msdn.microsoft.com/en-us/library/498928w2.aspx - /// + /// Releases the resources used by the object. public void Dispose () { Dispose (true); } - /// + /// Releases the resources used by the object. + /// If set to , the method is invoked directly and will dispose managed and unmanaged resources; If set to the method is being called by the garbage collector finalizer and should only release unmanaged resources. protected virtual void Dispose (bool disposing) { if (!owns || ptr == IntPtr.Zero) @@ -781,11 +745,11 @@ protected virtual void Dispose (bool disposing) } } - /// Class used to create audio files or read audio files. - /// - /// Use the Create, Open and OpenRead factory methods to create instances of this class. - /// This class provides access to the encoder and decoder for compressed audio files. - /// + /// Class used to create or read audio files. + /// + /// Use the Create, Open and OpenRead factory methods to create instances of this class. + /// This class provides access to the encoder and decoder for compressed audio files. + /// [SupportedOSPlatform ("ios")] [SupportedOSPlatform ("maccatalyst")] [SupportedOSPlatform ("macos")] @@ -805,7 +769,7 @@ internal AudioFile (NativeHandle handle, bool owns) [DllImport (Constants.AudioToolboxLibrary)] extern static OSStatus AudioFileClose (AudioFileID handle); - /// + /// protected override void Dispose (bool disposing) { if (Handle != IntPtr.Zero && Owns) @@ -814,8 +778,6 @@ protected override void Dispose (bool disposing) } /// Audio file size, in bytes. - /// - /// To be added. public long Length { get { return GetLong (AudioFileProperty.AudioDataByteCount); @@ -823,16 +785,9 @@ public long Length { } [DllImport (Constants.AudioToolboxLibrary)] - unsafe extern static OSStatus AudioFileCreateWithURL (IntPtr cfurlref_infile, AudioFileType inFileType, AudioStreamBasicDescription* inFormat, AudioFileFlags inFlags, AudioFileID* file_id); - - /// The url of the file to create - /// The file type for the created file - /// Description of the data that is going to be passed to the AudioFile object - /// Creation flags. - /// Creates a new audio file. - /// The initialized audio file, or null if there is an error creating the file - /// - /// + unsafe extern static AudioFileError AudioFileCreateWithURL (IntPtr cfurlref_infile, AudioFileType inFileType, AudioStreamBasicDescription* inFormat, AudioFileFlags inFlags, AudioFileID* file_id); + + /// public static AudioFile? Create (string url, AudioFileType fileType, AudioStreamBasicDescription format, AudioFileFlags inFlags) { if (url is null) @@ -842,142 +797,138 @@ public long Length { return Create (cfurl, fileType, format, inFlags); } - /// The url of the file to create - /// The file type for the created file - /// Description of the data that is going to be passed to the AudioFile object - /// Creation flags. - /// Creates a new audio file. - /// The initialized audio file, or null if there is an error creating the file - /// - /// + /// Create a new audio file. + /// The url of the file to create. + /// The file type for the created file. + /// Description of the data that is going to be passed to the object. + /// Creation flags. + /// The initialized audio file, or if there is an error creating the file. public static AudioFile? Create (CFUrl url, AudioFileType fileType, AudioStreamBasicDescription format, AudioFileFlags inFlags) { - if (url is null) - ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (url)); - - var h = default (IntPtr); + return Create (url, fileType, format, inFlags, out var _); + } - unsafe { - var urlHandle = url.Handle; - if (AudioFileCreateWithURL (urlHandle, fileType, &format, inFlags, &h) == 0) { - GC.KeepAlive (url); - return new AudioFile (h, true); - } - } - return null; + /// Create a new audio file. + /// The url of the file to create. + /// The file type for the created file. + /// Description of the data that is going to be passed to the object. + /// Creation flags. + /// if successful, or an error code otherwise. + /// The initialized audio file, or if there is an error creating the file. + public static AudioFile? Create (CFUrl url, AudioFileType fileType, AudioStreamBasicDescription format, AudioFileFlags inFlags, out AudioFileError status) + { + var rv = Create (url.GetNonNullHandle (nameof (url)), fileType, format, inFlags, out status); + GC.KeepAlive (url); + return rv; } - /// The url of the file to create - /// The file type for the created file - /// Description of the data that is going to be passed to the AudioFile object - /// Creation flags. - /// Creates a new audio file. - /// The initialized audio file, or null if there is an error creating the file - /// - /// + /// public static AudioFile? Create (NSUrl url, AudioFileType fileType, AudioStreamBasicDescription format, AudioFileFlags inFlags) { - if (url is null) - ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (url)); + return Create (url, fileType, format, inFlags, out var _); + } + /// + public static AudioFile? Create (NSUrl url, AudioFileType fileType, AudioStreamBasicDescription format, AudioFileFlags inFlags, out AudioFileError status) + { + var rv = Create (url.GetNonNullHandle (nameof (url)), fileType, format, inFlags, out status); + GC.KeepAlive (url); + return rv; + } + + static AudioFile? Create (IntPtr url, AudioFileType fileType, AudioStreamBasicDescription format, AudioFileFlags inFlags, out AudioFileError status) + { var h = default (IntPtr); unsafe { - var urlHandle = url.Handle; - if (AudioFileCreateWithURL (urlHandle, fileType, &format, inFlags, &h) == 0) { - GC.KeepAlive (url); - return new AudioFile (h, true); - } + status = AudioFileCreateWithURL (url, fileType, &format, inFlags, &h); } + + if (status == AudioFileError.Success && h != IntPtr.Zero) + return new AudioFile (h, true); + return null; } - [DllImport (Constants.AudioToolboxLibrary)] unsafe extern static AudioFileError AudioFileOpenURL (IntPtr cfurlref_infile, byte permissions, AudioFileType fileTypeHint, IntPtr* file_id); - /// An url to a local file name. - /// A hint indicating the file format expected, this is necessary for audio files where the operating system can not probe the type by looking at the file signature or file extension (for example AC3. Pass zero to auto detect the format. - /// Opens an audio file for reading. - /// An instance of AudioFile on success, or null on error. - /// The hint is necessary as sometimes it is not possible to determine the file type merely based on the contents of the file. + /// Opens an audio file for reading. + /// A url to a local file name. + /// A hint indicating the file format expected, this is necessary for audio files where the operating system can not probe the type by looking at the file signature or file extension (for example AC3). Pass zero to auto detect the format. + /// An instance of on success, or on error. + /// + /// The hint is necessary as sometimes it is not possible to determine the file type merely based on the contents of the file. + /// Once you have opened the file for reading, you can use the various Read methods to decode the audio packets contained in the file. + /// public static AudioFile? OpenRead (string url, AudioFileType fileTypeHint = 0) { return Open (url, AudioFilePermission.Read, fileTypeHint); } - /// To be added. - /// To be added. - /// To be added. - /// Opens an audio file for reading. - /// An instance of AudioFile on success, or null on error. - /// The hint is necessary as sometimes it is not possible to determine the file type merely based on the contents of the file. + /// Opens an audio file for reading. + /// A url to a local file name. + /// if successful, or an error code otherwise. + /// A hint indicating the file format expected, this is necessary for audio files where the operating system can not probe the type by looking at the file signature or file extension (for example AC3). Pass zero to auto detect the format. + /// An instance of on success, or on error. + /// + /// The hint is necessary as sometimes it is not possible to determine the file type merely based on the contents of the file. + /// Once you have opened the file for reading, you can use the various Read methods to decode the audio packets contained in the file. + /// public static AudioFile? OpenRead (string url, out AudioFileError error, AudioFileType fileTypeHint = 0) { return Open (url, AudioFilePermission.Read, out error, fileTypeHint); } - /// Url pointing to the file to read. - /// A hint indicating the file format expected, this is necessary for audio files where the operating system can not probe the type by looking at the file signature or file extension (for example AC3. Pass zero to auto detect the format. - /// Opens the specified audio file for reading, frames will be decoded from the native format to raw audio data. - /// An instance of AudioFile on success, or null on error. - /// Once you have opened the file for reading, you can use the various Read methods to decode the audio packets contained in the file. + /// public static AudioFile? OpenRead (CFUrl url, AudioFileType fileTypeHint = 0) { return Open (url, AudioFilePermission.Read, fileTypeHint); } - /// To be added. - /// To be added. - /// To be added. - /// Opens an audio file for reading. - /// An instance of AudioFile on success, or null on error. - /// The hint is necessary as sometimes it is not possible to determine the file type merely based on the contents of the file. + /// public static AudioFile? OpenRead (CFUrl url, out AudioFileError error, AudioFileType fileTypeHint = 0) { return Open (url, AudioFilePermission.Read, out error, fileTypeHint); } - /// Url pointing to the file to read. - /// A hint indicating the file format expected, this is necessary for audio files where the operating system can not probe the type by looking at the file signature or file extension (for example AC3. Pass zero to auto detect the format. - /// Opens the specified audio file for reading, frames will be decoded from the native format to raw audio data. - /// An instance of AudioFile on success, or null on error. - /// Once you have opened the file for reading, you can use the various Read methods to decode the audio packets contained in the file. + /// public static AudioFile? OpenRead (NSUrl url, AudioFileType fileTypeHint = 0) { return Open (url, AudioFilePermission.Read, fileTypeHint); } - /// To be added. - /// To be added. - /// To be added. - /// Opens an audio file for reading. - /// An instance of AudioFile on success, or null on error. - /// The hint is necessary as sometimes it is not possible to determine the file type merely based on the contents of the file. + /// public static AudioFile? OpenRead (NSUrl url, out AudioFileError error, AudioFileType fileTypeHint = 0) { return Open (url, AudioFilePermission.Read, out error, fileTypeHint); } - /// To be added. - /// To be added. - /// A hint for the decoder. - /// Opens an audio file. - /// An instance of AudioFile on success, null on failure. - /// The hint is necessary as sometimes it is not possible to determine the file type merely based on the contents of the file. + /// Opens an audio file for reading. + /// A url to a local file name. + /// The permissions to use when opening the file. + /// A hint indicating the file format expected, this is necessary for audio files where the operating system can not probe the type by looking at the file signature or file extension (for example AC3). Pass zero to auto detect the format. + /// An instance of on success, or on error. + /// + /// The hint is necessary as sometimes it is not possible to determine the file type merely based on the contents of the file. + /// Once you have opened the file for reading, you can use the various Read methods to decode the audio packets contained in the file. + /// public static AudioFile? Open (string url, AudioFilePermission permissions, AudioFileType fileTypeHint = 0) { AudioFileError error; return Open (url, permissions, out error, fileTypeHint); } - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// Opens an audio file. - /// An instance of AudioFile on success, null on failure. - /// The hint is necessary as sometimes it is not possible to determine the file type merely based on the contents of the file. + /// Opens an audio file for reading. + /// A url to a local file name. + /// The permissions to use when opening the file. + /// if successful, or an error code otherwise. + /// A hint indicating the file format expected, this is necessary for audio files where the operating system can not probe the type by looking at the file signature or file extension (for example AC3). Pass zero to auto detect the format. + /// An instance of on success, or on error. + /// + /// The hint is necessary as sometimes it is not possible to determine the file type merely based on the contents of the file. + /// Once you have opened the file for reading, you can use the various Read methods to decode the audio packets contained in the file. + /// public static AudioFile? Open (string url, AudioFilePermission permissions, out AudioFileError error, AudioFileType fileTypeHint = 0) { if (url is null) @@ -987,25 +938,14 @@ public long Length { return Open (cfurl, permissions, out error, fileTypeHint); } - /// The url to a local file name. - /// The permissions used for the file (reading, writing or both). - /// A hint for the decoder. - /// Opens an audio file. - /// An instance of AudioFile on success, null on failure. - /// The hint is necessary as sometimes it is not possible to determine the file type merely based on the contents of the file. + /// public static AudioFile? Open (CFUrl url, AudioFilePermission permissions, AudioFileType fileTypeHint = 0) { AudioFileError error; return Open (url, permissions, out error, fileTypeHint); } - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// Opens an audio file. - /// An instance of AudioFile on success, null on failure. - /// The hint is necessary as sometimes it is not possible to determine the file type merely based on the contents of the file. + /// public static AudioFile? Open (CFUrl url, AudioFilePermission permissions, out AudioFileError error, AudioFileType fileTypeHint = 0) { if (url is null) @@ -1016,25 +956,14 @@ public long Length { return audioFile; } - /// To be added. - /// To be added. - /// To be added. - /// Opens an audio file. - /// An instance of AudioFile on success, null on failure. - /// The hint is necessary as sometimes it is not possible to determine the file type merely based on the contents of the file. + /// public static AudioFile? Open (NSUrl url, AudioFilePermission permissions, AudioFileType fileTypeHint = 0) { AudioFileError error; return Open (url, permissions, out error, fileTypeHint); } - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// Opens an audio file. - /// An instance of AudioFile on success, null on failure. - /// The hint is necessary as sometimes it is not possible to determine the file type merely based on the contents of the file. + /// public static AudioFile? Open (NSUrl url, AudioFilePermission permissions, out AudioFileError error, AudioFileType fileTypeHint = 0) { if (url is null) @@ -1060,8 +989,6 @@ public long Length { extern static OSStatus AudioFileOptimize (AudioFileID handle); /// Optimizes the audio file, thus preparing it to receive audio data. - /// To be added. - /// To be added. public bool Optimize () { return AudioFileOptimize (Handle) == 0; @@ -1070,14 +997,14 @@ public bool Optimize () [DllImport (Constants.AudioToolboxLibrary)] unsafe extern static OSStatus AudioFileReadBytes (AudioFileID inAudioFile, byte useCache, long startingByte, int* numBytes, IntPtr outBuffer); - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// Reads bytes from , starting at . - /// To be added. - /// To be added. + /// Reads bytes from , starting at . + /// The starting byte in the file where the data will be read. + /// The buffer that holds the data. + /// The offset within the buffer where the audio data will stored. + /// The number of bytes to read from the file. + /// Whether the data should be cached. + /// The number of bytes read from the file, or -1 on error. + /// This API merely reads bytes from the file without any encoding. Use any of the ReadPacketData to read with encoding. public int Read (long startingByte, byte [] buffer, int offset, int count, bool useCache) { if (offset < 0) @@ -1109,45 +1036,43 @@ public int Read (long startingByte, byte [] buffer, int offset, int count, bool } [DllImport (Constants.AudioToolboxLibrary)] - unsafe extern static OSStatus AudioFileWriteBytes (AudioFileID audioFile, byte useCache, long startingByte, int* numBytes, IntPtr buffer); + unsafe extern static AudioFileError AudioFileWriteBytes (AudioFileID audioFile, byte useCache, long startingByte, int* numBytes, IntPtr buffer); + /// Writes a block of data to the audio file. /// The starting byte in the file where the data will be written. - /// The buffer that holds the data. - /// The offset within the buffer where the data to be saved starts. - /// The number of bytes to write to the file. - /// Whether the data should be cached. - /// Writes a block of data to the audio file. - /// The number of bytes written to the stream, or -1 on error. - /// This API merely writes bytes to the file without any encoding. Use WritePackets to write with encoding. + /// The buffer that holds the data. + /// The offset within the buffer where the data to be saved starts. + /// The number of bytes to write to the file. + /// Whether the data should be cached. + /// The number of bytes written to the stream, or -1 on error. + /// This API merely writes bytes to the file without any encoding. Use any of the WritePackets overloads to write with encoding. public int Write (long startingByte, byte [] buffer, int offset, int count, bool useCache) { - if (offset < 0) - throw new ArgumentOutOfRangeException (nameof (offset), "< 0"); - if (count < 0) - throw new ArgumentOutOfRangeException (nameof (count), "< 0"); - if (offset > buffer.Length - count) - throw new ArgumentException ("Reading would overrun buffer"); - - unsafe { - fixed (byte* p = &buffer [offset]) { - if (AudioFileWriteBytes (Handle, useCache ? (byte) 1 : (byte) 0, startingByte, &count, (IntPtr) p) == 0) - return count; - else - return -1; - } - } + return Write (startingByte, buffer, offset, count, useCache, out AudioFileError _); } - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// Writes data to an audo file. - /// To be added. - /// To be added. +#if !XAMCORE_5_0 + /// + [EditorBrowsable (EditorBrowsableState.Never)] + [Obsolete ("Use 'Write (long, byte[], int, int, bool, out AudioFileError)' instead.")] public int Write (long startingByte, byte [] buffer, int offset, int count, bool useCache, out int errorCode) + { + var rv = Write (startingByte, buffer, offset, count, useCache, out AudioFileError error); + errorCode = (int) error; + return rv; + } +#endif // !XAMCORE_5_0 + + /// Writes a block of data to the audio file. + /// The starting byte in the file where the data will be written. + /// The buffer that holds the data. + /// The offset within the buffer where the data to be saved starts. + /// The number of bytes to write to the file. + /// Whether the data should be cached. + /// if successful, or an error code otherwise. + /// The number of bytes written to the stream, or -1 on error. + /// This API merely writes bytes to the file without any encoding. Use any of the WritePackets overloads to write with encoding. + public int Write (long startingByte, byte [] buffer, int offset, int count, bool useCache, out AudioFileError errorCode) { if (offset < 0) throw new ArgumentOutOfRangeException (nameof (offset), "< 0"); @@ -1172,26 +1097,23 @@ unsafe extern static OSStatus AudioFileReadPacketData ( AudioFileID audioFile, byte useCache, int* numBytes, AudioStreamPacketDescription* packetDescriptions, long inStartingPacket, int* numPackets, IntPtr outBuffer); + /// Reads packets of audio data from an audio file. /// The index of the first packet to read. - /// The number of packets to read. - /// The output buffer where packets are written. - /// Reads packets of audio data from an audio file. - /// Array of packet descriptors for the packets that were read. - /// - /// + /// The number of packets to read. + /// The output buffer where packets are written. + /// Array of packet descriptors for the packets that were read. public AudioStreamPacketDescription []? ReadPacketData (long inStartingPacket, int nPackets, byte [] buffer) { AudioFileError error; return ReadPacketData (inStartingPacket, nPackets, buffer, out error); } - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// Reads packets of audio data. - /// To be added. - /// To be added. + /// Reads packets of audio data from an audio file. + /// The index of the first packet to read. + /// The number of packets to read. + /// The output buffer where packets are written. + /// if successful, or an error code otherwise. + /// Array of packet descriptors for the packets that were read. public AudioStreamPacketDescription []? ReadPacketData (long inStartingPacket, int nPackets, byte [] buffer, out AudioFileError error) { if (buffer is null) @@ -1200,31 +1122,28 @@ unsafe extern static OSStatus AudioFileReadPacketData ( return RealReadPacketData (false, inStartingPacket, ref nPackets, buffer, 0, ref count, out error); } + /// Reads packets of audio data from an audio file. /// If the data should be cached. - /// The index of the first packet to read. - /// The number of packets to read. - /// The output buffer where packets are written. - /// The offset in the output buffer where to start writing packets to. - /// The size of the output buffer (in bytes). - /// Reads packets of audio data from an audio file. - /// Array of packet descriptors for the packets that were read. - /// - /// + /// The index of the first packet to read. + /// The number of packets to read. + /// The output buffer where packets are written. + /// The offset in the output buffer where to start writing packets to. + /// The size of the output buffer (in bytes). + /// Array of packet descriptors for the packets that were read. public AudioStreamPacketDescription []? ReadPacketData (bool useCache, long inStartingPacket, int nPackets, byte [] buffer, int offset, int count) { return ReadPacketData (useCache, inStartingPacket, ref nPackets, buffer, offset, ref count); } - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// Reads packets of audio data. - /// To be added. - /// To be added. + /// Reads packets of audio data from an audio file. + /// If the data should be cached. + /// The index of the first packet to read. + /// The number of packets to read. + /// The output buffer where packets are written. + /// The offset in the output buffer where to start writing packets to. + /// The size of the output buffer (in bytes). + /// if successful, or an error code otherwise. + /// Array of packet descriptors for the packets that were read. public AudioStreamPacketDescription []? ReadPacketData (bool useCache, long inStartingPacket, int nPackets, byte [] buffer, int offset, int count, out AudioFileError error) { return ReadPacketData (useCache, inStartingPacket, ref nPackets, buffer, offset, ref count, out error); @@ -1247,32 +1166,29 @@ unsafe extern static OSStatus AudioFileReadPacketData ( return ret; } + /// Reads packets of audio data from an audio file. /// If the data should be cached. - /// The index of the first packet to read. - /// On input the number of packets to read, upon return the number of packets actually read. - /// The output buffer where packets are written. - /// The offset in the output buffer where to start writing packets to. - /// On input the size of the output buffer (in bytes), upon return the actual number of bytes read. - /// Reads packets of audio data from an audio file. - /// Array of packet descriptors for the packets that were read. - /// - /// + /// The index of the first packet to read. + /// On input the number of packets to read, upon return the number of packets actually read. + /// The output buffer where packets are written. + /// The offset in the output buffer where to start writing packets to. + /// On input the size of the output buffer (in bytes), upon return the actual number of bytes read. + /// Array of packet descriptors for the packets that were read. public AudioStreamPacketDescription []? ReadPacketData (bool useCache, long inStartingPacket, ref int nPackets, byte [] buffer, int offset, ref int count) { AudioFileError error; return ReadPacketData (useCache, inStartingPacket, ref nPackets, buffer, offset, ref count, out error); } - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// Reads packets of audio data. - /// To be added. - /// To be added. + /// Reads packets of audio data from an audio file. + /// If the data should be cached. + /// The index of the first packet to read. + /// On input the number of packets to read, upon return the number of packets actually read. + /// The output buffer where packets are written. + /// The offset in the output buffer where to start writing packets to. + /// On input the size of the output buffer (in bytes), upon return the actual number of bytes read. + /// if successful, or an error code otherwise. + /// Array of packet descriptors for the packets that were read. public AudioStreamPacketDescription []? ReadPacketData (bool useCache, long inStartingPacket, ref int nPackets, byte [] buffer, int offset, ref int count, out AudioFileError error) { if (buffer is null) @@ -1290,46 +1206,42 @@ unsafe extern static OSStatus AudioFileReadPacketData ( return RealReadPacketData (useCache, inStartingPacket, ref nPackets, buffer, offset, ref count, out error); } + /// Reads packets of audio data from an audio file. /// If the data should be cached. - /// The index of the first packet to read. - /// The number of packets to read. - /// The output buffer where packets are written. - /// On input the size of the output buffer (in bytes), upon return the actual number of bytes read. - /// Reads packets of audio data from an audio file. - /// Array of packet descriptors for the packets that were read. - /// - /// + /// The index of the first packet to read. + /// On input the number of packets to read, upon return the number of packets actually read. + /// The output buffer where packets are written. + /// On input the size of the output buffer (in bytes), upon return the actual number of bytes read. + /// Array of packet descriptors for the packets that were read. public AudioStreamPacketDescription []? ReadPacketData (bool useCache, long inStartingPacket, ref int nPackets, IntPtr buffer, ref int count) { AudioFileError error; return ReadPacketData (useCache, inStartingPacket, ref nPackets, buffer, ref count, out error); } - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// Reads packets of audio data. - /// To be added. - /// To be added. + /// Reads packets of audio data from an audio file. + /// If the data should be cached. + /// The index of the first packet to read. + /// On input the number of packets to read, upon return the number of packets actually read. + /// The output buffer where packets are written. + /// On input the size of the output buffer (in bytes), upon return the actual number of bytes read. + /// if successful, or an error code otherwise. + /// Array of packet descriptors for the packets that were read. public AudioStreamPacketDescription []? ReadPacketData (bool useCache, long inStartingPacket, ref int nPackets, IntPtr buffer, ref int count, out AudioFileError error) { var descriptions = new AudioStreamPacketDescription [nPackets]; return ReadPacketData (useCache, inStartingPacket, ref nPackets, buffer, ref count, out error, descriptions); } - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// Reads packets of audio data. - /// To be added. - /// To be added. + /// Reads packets of audio data from an audio file. + /// If the data should be cached. + /// The index of the first packet to read. + /// On input the number of packets to read, upon return the number of packets actually read. + /// The output buffer where packets are written. + /// On input the size of the output buffer (in bytes), upon return the actual number of bytes read. + /// if successful, or an error code otherwise. + /// An array of packet descriptions describing the returned packets. + /// Array of packet descriptors for the packets that were read. public unsafe AudioStreamPacketDescription []? ReadPacketData (bool useCache, long inStartingPacket, ref int nPackets, IntPtr buffer, ref int count, out AudioFileError error, AudioStreamPacketDescription [] descriptions) { if (buffer == IntPtr.Zero) @@ -1384,25 +1296,23 @@ unsafe extern static OSStatus AudioFileReadPacketData ( return descriptions; } - /// To be added. - /// To be added. - /// To be added. - /// Reads bytes into , starting at . - /// To be added. - /// To be added. + /// Reads bytes into , starting at . + /// The index of the first packet to read. + /// On input the number of packets to read, upon return the number of packets actually read. + /// The output buffer where packets are written. + /// Array of packet descriptors for the packets that were read. public AudioStreamPacketDescription []? ReadFixedPackets (long inStartingPacket, int nPackets, byte [] buffer) { AudioFileError error; return ReadFixedPackets (inStartingPacket, nPackets, buffer, out error); } - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// Reads a fixed amount of audio data. - /// To be added. - /// To be added. + /// Reads bytes into , starting at . + /// The index of the first packet to read. + /// On input the number of packets to read, upon return the number of packets actually read. + /// The output buffer where packets are written. + /// if successful, or an error code otherwise. + /// Array of packet descriptors for the packets that were read. public AudioStreamPacketDescription []? ReadFixedPackets (long inStartingPacket, int nPackets, byte [] buffer, out AudioFileError error) { if (buffer is null) @@ -1410,31 +1320,29 @@ unsafe extern static OSStatus AudioFileReadPacketData ( return RealReadFixedPackets (false, inStartingPacket, nPackets, buffer, 0, buffer.Length, out error); } - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// Reads a fixed amount of audio data. - /// To be added. - /// To be added. + /// Reads bytes into , starting at . + /// If the data should be cached. + /// The index of the first packet to read. + /// On input the number of packets to read, upon return the number of packets actually read. + /// The output buffer where packets are written. + /// The offset in the output buffer where to start writing packets to. + /// The number of bytes to read. + /// Array of packet descriptors for the packets that were read. public AudioStreamPacketDescription []? ReadFixedPackets (bool useCache, long inStartingPacket, int nPackets, byte [] buffer, int offset, int count) { AudioFileError error; return ReadFixedPackets (useCache, inStartingPacket, nPackets, buffer, offset, count, out error); } - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// Reads a fixed amount of audio data. - /// To be added. - /// To be added. + /// Reads bytes into , starting at . + /// If the data should be cached. + /// The index of the first packet to read. + /// On input the number of packets to read, upon return the number of packets actually read. + /// The output buffer where packets are written. + /// The offset in the output buffer where to start writing packets to. + /// The number of bytes to read. + /// if successful, or an error code otherwise. + /// Array of packet descriptors for the packets that were read. public AudioStreamPacketDescription []? ReadFixedPackets (bool useCache, long inStartingPacket, int nPackets, byte [] buffer, int offset, int count, out AudioFileError error) { if (buffer is null) @@ -1476,14 +1384,13 @@ unsafe extern static AudioFileError AudioFileWritePackets ( AudioFileID audioFile, byte useCache, int inNumBytes, AudioStreamPacketDescription* inPacketDescriptions, long inStartingPacket, int* numPackets, IntPtr buffer); - /// To be added. - /// The starting packet in the packetDescriptions that should be written. - /// To be added. - /// To be added. - /// To be added. - /// Writes packets to an audo file. - /// To be added. - /// To be added. + /// Write audio packets to the audio file. + /// Whether the data should be kept in the cache. + /// The starting packet that should be written. + /// The number of packets to write. + /// The buffer containing the audio data. + /// The number of bytes to write. + /// The number of packets written or -1 on error. public int WritePackets (bool useCache, long startingPacket, int numPackets, IntPtr buffer, int byteCount) { if (buffer == IntPtr.Zero) @@ -1497,14 +1404,13 @@ public int WritePackets (bool useCache, long startingPacket, int numPackets, Int return -1; } + /// Write audio packets to the audio file. /// Whether the data should be kept in the cache. - /// The starting packet in the packetDescriptions that should be written. - /// An array of packet descriptions that describe the content of the buffer. - /// The buffer containing the audio data. - /// To be added. - /// Write audio packets to the audio file. - /// The number of packets written or -1 on error. - /// To be added. + /// The starting packet in the that should be written. + /// An array of packet descriptions that describe the content of the buffer. + /// The buffer containing the audio data. + /// The number of bytes to write. + /// The number of packets written or -1 on error. public int WritePackets (bool useCache, long startingPacket, AudioStreamPacketDescription [] packetDescriptions, IntPtr buffer, int byteCount) { if (packetDescriptions is null) @@ -1521,15 +1427,14 @@ public int WritePackets (bool useCache, long startingPacket, AudioStreamPacketDe return -1; } + /// Write audio packets to the audio file. /// Whether the data should be kept in the cache. - /// The starting packet in the packetDescriptions that should be written. - /// An array of packet descriptions that describe the contents of the buffer. - /// The buffer containing the audio data. - /// The first packet to write from the packetDescriptions. - /// To be added. - /// Writes audio packets to the file. - /// The number of packets written or -1 on error. - /// To be added. + /// The starting packet in the that should be written. + /// An array of packet descriptions that describe the content of the buffer. + /// The buffer containing the audio data. + /// The offset in the output buffer where to start writing packets to. + /// The number of bytes to write. + /// The number of packets written or -1 on error. unsafe public int WritePackets (bool useCache, long startingPacket, AudioStreamPacketDescription [] packetDescriptions, byte [] buffer, int offset, int byteCount) { if (packetDescriptions is null) @@ -1553,16 +1458,15 @@ unsafe public int WritePackets (bool useCache, long startingPacket, AudioStreamP } } + /// Write audio packets to the audio file. /// Whether the data should be kept in the cache. - /// The starting packet in the packetDescriptions that should be written. - /// An array of packet descriptions that describe the content of the buffer. - /// To be added. - /// To be added. - /// To be added. - /// Writes packets to an audo file. - /// To be added. - /// To be added. - public int WritePackets (bool useCache, long startingPacket, AudioStreamPacketDescription [] packetDescriptions, IntPtr buffer, int byteCount, out int errorCode) + /// The starting packet in the that should be written. + /// An array of packet descriptions that describe the content of the buffer. + /// The buffer containing the audio data. + /// The number of bytes to write. + /// if successful, or an error code otherwise. + /// The number of packets written or -1 on error. + public int WritePackets (bool useCache, long startingPacket, AudioStreamPacketDescription [] packetDescriptions, IntPtr buffer, int byteCount, out AudioFileError errorCode) { if (packetDescriptions is null) ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (packetDescriptions)); @@ -1572,7 +1476,7 @@ public int WritePackets (bool useCache, long startingPacket, AudioStreamPacketDe unsafe { fixed (AudioStreamPacketDescription* packetDescriptionsPtr = packetDescriptions) { - errorCode = (int) AudioFileWritePackets (Handle, useCache ? (byte) 1 : (byte) 0, byteCount, packetDescriptionsPtr, startingPacket, &nPackets, buffer); + errorCode = AudioFileWritePackets (Handle, useCache ? (byte) 1 : (byte) 0, byteCount, packetDescriptionsPtr, startingPacket, &nPackets, buffer); } } if (errorCode == 0) @@ -1580,17 +1484,28 @@ public int WritePackets (bool useCache, long startingPacket, AudioStreamPacketDe return -1; } +#if !XAMCORE_5_0 + /// + [EditorBrowsable (EditorBrowsableState.Never)] + [Obsolete ("Use 'WritePackets (bool, long, AudioStreamPacketDescription[], IntPtr, int, out AudioFileError)' instead.")] + public int WritePackets (bool useCache, long startingPacket, AudioStreamPacketDescription [] packetDescriptions, IntPtr buffer, int byteCount, out int errorCode) + { + var rv = WritePackets (useCache, startingPacket, packetDescriptions, buffer, byteCount, out AudioFileError error); + errorCode = (int) error; + return rv; + } +#endif // !XAMCORE_5_0 + + /// Write audio packets to the audio file. /// Whether the data should be kept in the cache. - /// The starting packet in the packetDescriptions that should be written. - /// An array of packet descriptions that describe the content of the buffer. - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// Writes packets to an audo file. - /// To be added. - /// To be added. - unsafe public int WritePackets (bool useCache, long startingPacket, AudioStreamPacketDescription [] packetDescriptions, byte [] buffer, int offset, int byteCount, out int errorCode) + /// The starting packet in the that should be written. + /// An array of packet descriptions that describe the content of the buffer. + /// The buffer containing the audio data. + /// The offset in the output buffer where to start writing packets to. + /// The number of bytes to write. + /// if successful, or an error code otherwise. + /// The number of packets written or -1 on error. + unsafe public int WritePackets (bool useCache, long startingPacket, AudioStreamPacketDescription [] packetDescriptions, byte [] buffer, int offset, int byteCount, out AudioFileError errorCode) { if (packetDescriptions is null) ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (packetDescriptions)); @@ -1606,7 +1521,7 @@ unsafe public int WritePackets (bool useCache, long startingPacket, AudioStreamP int nPackets = packetDescriptions.Length; fixed (byte* bop = &buffer [offset]) { fixed (AudioStreamPacketDescription* packetDescriptionsPtr = packetDescriptions) { - errorCode = (int) AudioFileWritePackets (Handle, useCache ? (byte) 1 : (byte) 0, byteCount, packetDescriptionsPtr, startingPacket, &nPackets, (IntPtr) bop); + errorCode = AudioFileWritePackets (Handle, useCache ? (byte) 1 : (byte) 0, byteCount, packetDescriptionsPtr, startingPacket, &nPackets, (IntPtr) bop); } if (errorCode == 0) return nPackets; @@ -1614,16 +1529,26 @@ unsafe public int WritePackets (bool useCache, long startingPacket, AudioStreamP } } +#if !XAMCORE_5_0 + /// + [EditorBrowsable (EditorBrowsableState.Never)] + [Obsolete ("Use 'WritePackets (bool, long, AudioStreamPacketDescription[], byte[], int, int, out AudioFileError)' instead.")] + public int WritePackets (bool useCache, long startingPacket, AudioStreamPacketDescription [] packetDescriptions, byte [] buffer, int offset, int byteCount, out int errorCode) + { + var rv = WritePackets (useCache, startingPacket, packetDescriptions, buffer, offset, byteCount, out AudioFileError error); + errorCode = (int) error; + return rv; + } +#endif // !XAMCORE_5_0 + /// Whether the data should be kept in the cache. - /// The number of bytes to write. - /// An array of packet descriptions that describe the content of the buffer. - /// The starting packet in the packetDescriptions that should be written. - /// The number of packets to write replaced with the number of packets actually written. - /// The buffer containing the audio data. - /// Writes audio packets to the file. - /// A status error code. - /// - /// + /// The number of bytes to write. + /// An array of packet descriptions that describe the content of the buffer. + /// The starting packet in the that should be written. + /// On input the number of packets to write, upon return the number of packets actually written. + /// The buffer containing the audio data. + /// Write audio packets to the audio file. + /// if successful, or an error code otherwise. public AudioFileError WritePackets (bool useCache, int numBytes, AudioStreamPacketDescription [] packetDescriptions, long startingPacket, ref int numPackets, IntPtr buffer) { if (buffer == IntPtr.Zero) @@ -1665,7 +1590,7 @@ public int CountUserData (AudioFileChunkType chunkType) /// Get the size of the specified user data. /// The fourcc of the chunk. - /// The index of the chunk if there are more than one chunk. + /// The index of the chunk if there are more than one chunks. /// Returns the (non-negative) size on success, otherwise -1. public int GetUserDataSize (uint userDataId, int index) { @@ -1680,7 +1605,7 @@ public int GetUserDataSize (uint userDataId, int index) /// Get the size of the specified user data. /// The fourcc of the chunk. - /// The index of the chunk if there are more than one chunk. + /// The index of the chunk if there are more than one chunks. /// Returns the (non-negative) size on success, otherwise -1. public int GetUserDataSize (AudioFileChunkType chunkType, int index) { @@ -1696,7 +1621,7 @@ public int GetUserDataSize (AudioFileChunkType chunkType, int index) /// Get the 64-bit size of the specified user data. /// The fourcc of the chunk. - /// The index of the chunk if there are more than one chunk. + /// The index of the chunk if there are more than one chunks. /// The retrieved 64-bit size of the specified user data. /// Returns on success, otherwise an error code. [SupportedOSPlatform ("ios17.0")] @@ -1713,7 +1638,7 @@ public AudioFileError GetUserDataSize (uint userDataId, int index, out ulong siz /// Get the 64-bit size of the specified user data. /// The fourcc of the chunk. - /// The index of the chunk if there are more than one chunk. + /// The index of the chunk if there are more than one chunks. /// The retrieved 64-bit size of the specified user data. /// Returns on success, otherwise an error code. [SupportedOSPlatform ("ios17.0")] @@ -1730,7 +1655,7 @@ public AudioFileError GetUserDataSize (AudioFileChunkType chunkType, int index, /// Get part of the data of a chunk in a file. /// The fourcc of the chunk. - /// The index of the chunk if there are more than one chunk. + /// The index of the chunk if there are more than one chunks. /// On input the size of the memory points to. On output the number of bytes written. /// A pointer to memory where the data will be copied. /// Returns on success, otherwise an error code. @@ -1747,7 +1672,7 @@ public int GetUserData (int userDataID, int index, ref int size, IntPtr userData /// Get part of the data of a chunk in a file. /// The fourcc of the chunk. - /// The index of the chunk if there are more than one chunk. + /// The index of the chunk if there are more than one chunks. /// On input the size of the memory points to. On output the number of bytes written. /// A pointer to memory where the data will be copied. /// Returns on success, otherwise an error code. @@ -1765,7 +1690,7 @@ public AudioFileError GetUserData (AudioFileChunkType chunkType, int index, ref /// Get part of the data of a chunk in a file. /// The fourcc of the chunk. - /// The index of the chunk if there are more than one chunk. + /// The index of the chunk if there are more than one chunks. /// The offset from the first byte of the chunk of the data to get. /// On input the size of the memory points to. On output the number of bytes written. /// A pointer to memory where the data will be copied. @@ -1783,7 +1708,7 @@ public AudioFileError GetUserData (uint userDataId, int index, long offset, ref /// Get part of the data of a chunk in a file. /// The fourcc of the chunk. - /// The index of the chunk if there are more than one chunk. + /// The index of the chunk if there are more than one chunks. /// The offset from the first byte of the chunk of the data to get. /// On input the size of the memory points to. On output the number of bytes written. /// A pointer to memory where the data will be copied. @@ -1799,7 +1724,7 @@ public AudioFileError GetUserData (AudioFileChunkType chunkType, int index, long /// Get part of the data of a chunk in a file. /// The fourcc of the chunk. - /// The index of the chunk if there are more than one chunk. + /// The index of the chunk if there are more than one chunks. /// The offset from the first byte of the chunk of the data to get. /// The number of bytes written into the byte array. /// An array of bytes where the data will be copied. @@ -1819,7 +1744,7 @@ public AudioFileError GetUserData (uint userDataId, int index, long offset, byte /// Get part of the data of a chunk in a file. /// The fourcc of the chunk. - /// The index of the chunk if there are more than one chunk. + /// The index of the chunk if there are more than one chunks. /// The offset from the first byte of the chunk of the data to get. /// The number of bytes written into the byte array. /// An array of bytes where the data will be copied. @@ -1834,76 +1759,149 @@ public AudioFileError GetUserData (AudioFileChunkType chunkType, int index, long } [DllImport (Constants.AudioToolboxLibrary)] - extern static OSStatus AudioFileSetUserData (AudioFileID inAudioFile, int userDataID, int index, int userDataSize, IntPtr userData); - - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// Sets the value at the specified into the specified to , which must have the size that is specified in . - /// To be added. - /// To be added. + extern static AudioFileError AudioFileSetUserData (AudioFileID inAudioFile, int userDataID, int index, int userDataSize, IntPtr userData); + +#if !XAMCORE_5_0 + /// Sets the value at the specified into the specified to , which must have the size that is specified in . + /// The fourcc of the chunk. + /// The index of the chunk if there are more than one chunks. + /// The number of bytes to write. + /// An array of bytes where the data will be copied. + /// Returns on success, otherwise an error code. + [EditorBrowsable (EditorBrowsableState.Never)] + [Obsolete ("Use 'SetUserData (AudioFileChunkType, int, byte[])' instead.")] public int SetUserData (int userDataId, int index, int userDataSize, IntPtr userData) { if (userData == IntPtr.Zero) ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (userData)); - return AudioFileSetUserData (Handle, userDataId, index, userDataSize, userData); + return (int) AudioFileSetUserData (Handle, userDataId, index, userDataSize, userData); + } +#endif // !XAMCORE_5_0 + + /// Set the data of a chunk in a file. + /// The fourcc of the chunk. + /// The index of the chunk if there are more than one chunks. + /// An array of bytes to set. + /// Returns on success, otherwise an error code. + public AudioFileError SetUserData (AudioFileChunkType chunkType, int index, byte [] data) + { + if (data is null) + ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (data)); + + unsafe { + fixed (byte* dataPtr = data) + return AudioFileSetUserData (GetCheckedHandle (), (int) chunkType, index, data.Length, (IntPtr) dataPtr); + } } [DllImport (Constants.AudioToolboxLibrary)] - extern static OSStatus AudioFileRemoveUserData (AudioFileID audioFile, int userDataID, int index); + extern static AudioFileError AudioFileRemoveUserData (AudioFileID audioFile, int userDataID, int index); - /// To be added. - /// To be added. - /// Removes the chunk of user data at the specified in the user data that is identified by . - /// To be added. - /// To be added. +#if !XAMCORE_5_0 + /// Removes the chunk of user data at the specified in the user data that is identified by . + /// The fourcc of the chunk. + /// The index of the chunk if there are more than one chunks. + /// Returns on success, otherwise an error code. + [EditorBrowsable (EditorBrowsableState.Never)] + [Obsolete ("Use 'RemoveUserData (AudioFileChunkType, int)' instead.")] public int RemoveUserData (int userDataId, int index) { - return AudioFileRemoveUserData (Handle, userDataId, index); + return (int) AudioFileRemoveUserData (Handle, userDataId, index); + } +#endif + + /// Removes the specified chunk of user data. + /// The fourcc of the chunk. + /// The index of the chunk if there are more than one chunks. + /// Returns on success, otherwise an error code. + public AudioFileError RemoveUserData (AudioFileChunkType chunkType, int index) + { + return AudioFileRemoveUserData (GetCheckedHandle (), (int) chunkType, index); } [DllImport (Constants.AudioToolboxLibrary)] - unsafe extern static OSStatus AudioFileGetPropertyInfo (AudioFileID audioFile, AudioFileProperty propertyID, int* outDataSize, int* isWritable); - - /// To be added. - /// To be added. - /// To be added. - /// Returns the value of the specified audio property, and stores the number of bytes allocated to store it in , and indicates whether the value is writeable. - /// To be added. - /// To be added. + unsafe extern static AudioFileError AudioFileGetPropertyInfo (AudioFileID audioFile, AudioFileProperty propertyID, int* outDataSize, int* isWritable); + +#if !XAMCORE_5_0 + /// Returns the value of the specified audio property, and stores the number of bytes allocated to store it in , and indicates whether the value is writeable. + /// The property whose info to get. + /// The size of the property. + /// Whether the property is writable or not. + /// Whether the operation succeeded or not. + [EditorBrowsable (EditorBrowsableState.Never)] + [Obsolete ("Use 'GetPropertyInfo (AudioFileProperty, out int, out bool)' instead.")] public bool GetPropertyInfo (AudioFileProperty property, out int size, out int writable) + { + return GetPropertyInfo (property, out size, out writable, out var _); + } + + /// Returns the value of the specified audio property, and stores the number of bytes allocated to store it in , and indicates whether the value is writeable. + /// The property whose info to get. + /// The size of the property. + /// Whether the property is writable or not. + /// if successful, or an error code otherwise. + /// Whether the operation succeeded or not. + [EditorBrowsable (EditorBrowsableState.Never)] + [Obsolete ("Use 'GetPropertyInfo (AudioFileProperty, out int, out bool, out AudioFileError)' instead.")] + public bool GetPropertyInfo (AudioFileProperty property, out int size, out int writable, out AudioFileError error) { size = default; writable = default; unsafe { - return AudioFileGetPropertyInfo (Handle, property, (int*) Unsafe.AsPointer (ref size), (int*) Unsafe.AsPointer (ref writable)) == 0; + error = AudioFileGetPropertyInfo (Handle, property, (int*) Unsafe.AsPointer (ref size), (int*) Unsafe.AsPointer (ref writable)); } + return error == AudioFileError.Success; + } +#endif + + /// Returns the value of the specified audio property, and stores the number of bytes allocated to store it in , and indicates whether the value is writeable. + /// The property whose info to get. + /// The size of the property. + /// Whether the property is writable or not. + /// Whether the operation succeeded or not. + public bool GetPropertyInfo (AudioFileProperty property, out int size, out bool writable) + { + return GetPropertyInfo (property, out size, out writable, out var _); + } + + /// Returns the value of the specified audio property, and stores the number of bytes allocated to store it in , and indicates whether the value is writeable. + /// The property whose info to get. + /// The size of the property. + /// Whether the property is writable or not. + /// if successful, or an error code otherwise. + /// Whether the operation succeeded or not. + public bool GetPropertyInfo (AudioFileProperty property, out int size, out bool writable, out AudioFileError error) + { + int writableValue = 0; + size = default; + + unsafe { + error = AudioFileGetPropertyInfo (Handle, property, (int*) Unsafe.AsPointer (ref size), &writableValue); + } + writable = writableValue != 0; + + return error == AudioFileError.Success; } /// The property being queried. - /// Checks whether the property value is settable. - /// - /// - /// - /// + /// Checks whether the property value is settable. + /// Whether the property value is settable or not. public bool IsPropertyWritable (AudioFileProperty property) { - return GetPropertyInfo (property, out var _, out var writable) && writable != 0; + return GetPropertyInfo (property, out var _, out bool writable) && writable; } [DllImport (Constants.AudioToolboxLibrary)] - unsafe extern static OSStatus AudioFileGetProperty (AudioFileID audioFile, AudioFileProperty property, int* dataSize, IntPtr outdata); + unsafe extern static AudioFileError AudioFileGetProperty (AudioFileID audioFile, AudioFileProperty property, int* dataSize, IntPtr outdata); [DllImport (Constants.AudioToolboxLibrary)] - unsafe extern static OSStatus AudioFileGetProperty (AudioFileID audioFile, AudioFileProperty property, int* dataSize, void* outdata); - - /// To be added. - /// To be added. - /// To be added. - /// Returns the value of the specified audio property, stores it in , and stores the number of bytes allocated to store it in . - /// To be added. - /// To be added. + unsafe extern static AudioFileError AudioFileGetProperty (AudioFileID audioFile, AudioFileProperty property, int* dataSize, void* outdata); + + /// Returns the value of the specified audio property, stores it in , and stores the number of bytes allocated to store it in . + /// The property to get. + /// On input the number of size of , upon return the number of packets bytes written. + /// A pointer to the memory where the property value will be stored. + /// Whether the operation succeeded or not. public bool GetProperty (AudioFileProperty property, ref int dataSize, IntPtr outdata) { unsafe { @@ -1911,16 +1909,14 @@ public bool GetProperty (AudioFileProperty property, ref int dataSize, IntPtr ou } } - /// To be added. - /// To be added. - /// Returns the value of the specified audio property, and stores the number of bytes allocated to store it in . - /// To be added. - /// To be added. + /// Returns the value of the specified audio property, and stores the number of bytes allocated to store it in . + /// The property to get. + /// Upon return, the size of the property. + /// A pointer to the value of the specified audio property, or in case of failure. + /// The caller is responsible for freeing the returned pointer, using . public IntPtr GetProperty (AudioFileProperty property, out int size) { - int writable; - - if (!GetPropertyInfo (property, out size, out writable)) + if (!GetPropertyInfo (property, out size, out bool _)) return IntPtr.Zero; var buffer = Marshal.AllocHGlobal (size); @@ -2016,12 +2012,11 @@ long GetLong (AudioFileProperty property) [DllImport (Constants.AudioToolboxLibrary)] unsafe extern static AudioFileError AudioFileSetProperty (AudioFileID audioFile, AudioFileProperty property, int dataSize, AudioFilePacketTableInfo* propertyData); - /// To be added. - /// To be added. - /// To be added. - /// Sets the value of the specified to , which must have the size that is specified in . - /// To be added. - /// To be added. + /// Sets the value of the specified to , which must have the size that is specified in . + /// The property to set. + /// The size of . + /// A pointer to the data to set. + /// Whether the operation succeeded or not. public bool SetProperty (AudioFileProperty property, int dataSize, IntPtr propertyData) { if (propertyData == IntPtr.Zero) @@ -2042,8 +2037,6 @@ unsafe AudioFileError SetDouble (AudioFileProperty property, double value) } /// Audio file type. - /// To be added. - /// To be added. public AudioFileType FileType { get { return (AudioFileType) GetInt (AudioFileProperty.FileFormat); @@ -2051,8 +2044,6 @@ public AudioFileType FileType { } /// The audio basic description, as determined by decoding the file. - /// - /// To be added. [Advice ("Use 'DataFormat' instead.")] public AudioStreamBasicDescription StreamBasicDescription { get { @@ -2061,13 +2052,9 @@ public AudioStreamBasicDescription StreamBasicDescription { } /// Gets the status of the stream's basic description. - /// To be added. - /// To be added. public AudioFileError StreamBasicDescriptionStatus { get; private set; } /// Gets the , if present, that describes the format of the audio data. - /// To be added. - /// To be added. public AudioStreamBasicDescription? DataFormat { get { return GetProperty (AudioFileProperty.DataFormat); @@ -2075,8 +2062,6 @@ public AudioStreamBasicDescription? DataFormat { } /// Returns a list of the supported audio formats. - /// To be added. - /// To be added. public AudioFormat []? AudioFormats { get { unsafe { @@ -2099,8 +2084,6 @@ public AudioFormat []? AudioFormats { } /// Gets a Boolean value that tells whether the audio file has been optimized and is ready to receive sound data. - /// To be added. - /// To be added. public bool IsOptimized { get { return GetInt (AudioFileProperty.IsOptimized) == 1; @@ -2108,8 +2091,7 @@ public bool IsOptimized { } /// The magic cookie for this file. - /// - /// Certain files require the magic cookie to be set before they can be written to. Set this property before you write packets from your source (AudioQueue). + /// Certain files require the magic cookie to be set before they can be written to. Set this property before you write packets from your source (AudioQueue). public byte [] MagicCookie { get { int size; @@ -2137,8 +2119,6 @@ public byte [] MagicCookie { } /// Gets the number of audio data packets in the audio file. - /// To be added. - /// To be added. public long DataPacketCount { get { return GetLong (AudioFileProperty.AudioDataPacketCount); @@ -2146,8 +2126,6 @@ public long DataPacketCount { } /// Gets the maximum audio packet size. - /// To be added. - /// To be added. public int MaximumPacketSize { get { return GetInt (AudioFileProperty.MaximumPacketSize); @@ -2155,8 +2133,6 @@ public int MaximumPacketSize { } /// Gets the offset, in bytes, to the beginning of the audio data in the audio file. - /// To be added. - /// To be added. public long DataOffset { get { return GetLong (AudioFileProperty.DataOffset); @@ -2164,8 +2140,6 @@ public long DataOffset { } /// Gets the album artwork for the audio file. - /// To be added. - /// To be added. public NSData? AlbumArtwork { get { return Runtime.GetNSObject (GetIntPtr (AudioFileProperty.AlbumArtwork)); @@ -2173,8 +2147,6 @@ public NSData? AlbumArtwork { } /// Gets the channel layout of the audio file. - /// To be added. - /// To be added. public AudioChannelLayout? ChannelLayout { get { int size; @@ -2189,9 +2161,7 @@ public AudioChannelLayout? ChannelLayout { } } - /// Gets or sets a Boolean value that controls whether the updating of file size information in the header will be deferred until the file is read, optimized, or closed. The default, which is safer, is - /// To be added. - /// To be added. + /// Gets or sets a boolean value that controls whether the updating of file size information in the header will be deferred until the file is read, optimized, or closed. The default, which is safer, is public bool DeferSizeUpdates { get { return GetInt (AudioFileProperty.DeferSizeUpdates) == 1; @@ -2202,8 +2172,6 @@ public bool DeferSizeUpdates { } /// Audio file bit rate. - /// To be added. - /// To be added. public int BitRate { get { return GetInt (AudioFileProperty.BitRate); @@ -2211,8 +2179,6 @@ public int BitRate { } /// Gets the estimated duration, in seconds, of the audio data in the file. - /// To be added. - /// To be added. public double EstimatedDuration { get { return GetDouble (AudioFileProperty.EstimatedDuration); @@ -2220,8 +2186,6 @@ public double EstimatedDuration { } /// Gets the theoretical upper bound for the audio packet size for audio data in the file. - /// To be added. - /// To be added. public int PacketSizeUpperBound { get { return GetInt (AudioFileProperty.PacketSizeUpperBound); @@ -2229,17 +2193,13 @@ public int PacketSizeUpperBound { } /// Gets the amount of recording time to reserve in the audio file. - /// To be added. - /// To be added. public double ReserveDuration { get { return GetDouble (AudioFileProperty.ReserveDuration); } } - /// Gets the that contains the markers for the audio file. - /// To be added. - /// To be added. + /// Gets the that contains the markers for the audio file. public AudioFileMarkerList? MarkerList { get { var ptr = GetProperty (AudioFileProperty.MarkerList, out var _); @@ -2251,8 +2211,6 @@ public AudioFileMarkerList? MarkerList { } /// Gets a list of all the audio regions in the audio file. - /// To be added. - /// To be added. public AudioFileRegionList? RegionList { get { var ptr = GetProperty (AudioFileProperty.RegionList, out var _); @@ -2264,13 +2222,9 @@ public AudioFileRegionList? RegionList { } /// Gets the status of the audio packet table.. - /// To be added. - /// To be added. public AudioFileError PacketTableInfoStatus { get; private set; } - /// Gets or sets the structure that describes the audio file packet table. - /// To be added. - /// To be added. + /// Gets or sets the structure that describes the audio file packet table. public unsafe AudioFilePacketTableInfo? PacketTableInfo { get { return GetProperty (AudioFileProperty.PacketTableInfo); @@ -2287,8 +2241,6 @@ public unsafe AudioFilePacketTableInfo? PacketTableInfo { } /// Gets an array of four-character codes that describe the kind of each chunk in the audio file. - /// To be added. - /// To be added. public unsafe AudioFileChunkType []? ChunkIDs { get { int size; @@ -2308,8 +2260,6 @@ public unsafe AudioFileChunkType []? ChunkIDs { } /// Gets a byte array that contains the ID3Tag for the audio data. - /// To be added. - /// To be added. public unsafe byte []? ID3Tag { get { int size; @@ -2328,9 +2278,7 @@ public unsafe byte []? ID3Tag { } } - /// Gets the CF dictionary that contains audio file metadata. - /// To be added. - /// To be added. + /// Gets the dictionary that contains audio file metadata. public AudioFileInfoDictionary? InfoDictionary { get { var ptr = GetIntPtr (AudioFileProperty.InfoDictionary); @@ -2341,10 +2289,9 @@ public AudioFileInfoDictionary? InfoDictionary { } } - /// To be added. - /// Returns the frame number for the specified . - /// To be added. - /// To be added. + /// Returns the frame number for the specified . + /// The packet whose frame number to get. + /// The frame number for the specified , or -1 in case of failure. public long PacketToFrame (long packet) { AudioFramePacketTranslation buffer = default; @@ -2358,11 +2305,10 @@ public long PacketToFrame (long packet) } } - /// The frame. - /// The offset inside the packet that the frame points to. - /// Converts an audio frame into a packet offset. - /// -1 on failure, otherwise the packet that represents the specified frame. Additionally, the offset within the packet is returned in the out parameter. - /// To be added. + /// Converts an audio frame into a packet offset. + /// The frame whose packet offset to get. + /// The offset inside the packet that the frame points to. + /// -1 on failure, otherwise the packet that represents the specified frame. Additionally, the offset within the packet is returned in . public long FrameToPacket (long frame, out int frameOffsetInPacket) { AudioFramePacketTranslation buffer = default; @@ -2379,11 +2325,10 @@ public long FrameToPacket (long frame, out int frameOffsetInPacket) } } - /// To be added. - /// To be added. - /// Returns the byte offset for the and indicates whether this is an estimated value in . - /// To be added. - /// To be added. + /// Returns the byte offset for the and indicates whether this is an estimated value in . + /// The packet whose byte offset to get. + /// Whether the returned value is accurate or an estimate. + /// The byte offset for the specified . public long PacketToByte (long packet, out bool isEstimate) { AudioBytePacketTranslation buffer = default; @@ -2400,12 +2345,11 @@ public long PacketToByte (long packet, out bool isEstimate) } } + /// Converts a position on a stream to its packet location. /// The byte position. - /// Offset within the packet. - /// True if the return value is an estimate. - /// Converts a position on a stream to its packet location. - /// The packet where the byte position would be, or -1 on error. - /// To be added. + /// Offset within the packet. + /// if the return value is an estimate. + /// The packet where the byte position would be, or -1 on error. public long ByteToPacket (long byteval, out int byteOffsetInPacket, out bool isEstimate) { AudioBytePacketTranslation buffer = default; @@ -2426,7 +2370,6 @@ public long ByteToPacket (long byteval, out int byteOffsetInPacket, out bool isE } /// Metadata-like information relating to a particular audio file. - /// To be added. [SupportedOSPlatform ("ios")] [SupportedOSPlatform ("maccatalyst")] [SupportedOSPlatform ("macos")] @@ -2437,198 +2380,154 @@ internal AudioFileInfoDictionary (NSDictionary dict) { } - /// To be added. - /// To be added. - /// To be added. + /// The album. public string? Album { get { return GetStringValue ("album"); } } - /// To be added. - /// To be added. - /// To be added. + /// An approximate duration in seconds. public string? ApproximateDurationInSeconds { get { return GetStringValue ("approximate duration in seconds"); } } - /// To be added. - /// To be added. - /// To be added. + /// The artist. public string? Artist { get { return GetStringValue ("artist"); } } - /// To be added. - /// To be added. - /// To be added. + /// The channel layout. public string? ChannelLayout { get { return GetStringValue ("channel layout"); } } - /// To be added. - /// To be added. - /// To be added. + /// The composer. public string? Composer { get { return GetStringValue ("composer"); } } - /// To be added. - /// To be added. - /// To be added. + /// Any comments. public string? Comments { get { return GetStringValue ("comments"); } } - /// To be added. - /// To be added. - /// To be added. + /// The copyright. public string? Copyright { get { return GetStringValue ("copyright"); } } - /// To be added. - /// To be added. - /// To be added. + /// The encoding application. public string? EncodingApplication { get { return GetStringValue ("encoding application"); } } - /// To be added. - /// To be added. - /// To be added. + /// The genre. public string? Genre { get { return GetStringValue ("genre"); } } - /// To be added. - /// To be added. - /// To be added. + /// The ISRC (International Standard Recording Code) value. public string? ISRC { get { return GetStringValue ("ISRC"); } } - /// To be added. - /// To be added. - /// To be added. + /// The key signature. public string? KeySignature { get { return GetStringValue ("key signature"); } } - /// To be added. - /// To be added. - /// To be added. + /// The lyricist. public string? Lyricist { get { return GetStringValue ("lyricist"); } } - /// To be added. - /// To be added. - /// To be added. + /// The nominal bitrate. public string? NominalBitRate { get { return GetStringValue ("nominal bit rate"); } } - /// To be added. - /// To be added. - /// To be added. + /// The recorded date. public string? RecordedDate { get { return GetStringValue ("recorded date"); } } - /// To be added. - /// To be added. - /// To be added. + /// The source bit depth. public string? SourceBitDepth { get { return GetStringValue ("source bit depth"); } } - /// To be added. - /// To be added. - /// To be added. + /// The source encoder. public string? SourceEncoder { get { return GetStringValue ("source encoder"); } } - /// To be added. - /// To be added. - /// To be added. + /// The subtitle. public string? SubTitle { get { return GetStringValue ("subtitle"); } } - /// To be added. - /// To be added. - /// To be added. + /// The tempo. public string? Tempo { get { return GetStringValue ("tempo"); } } - /// To be added. - /// To be added. - /// To be added. + /// The time signature. public string? TimeSignature { get { return GetStringValue ("time signature"); } } - /// To be added. - /// To be added. - /// To be added. + /// The title. public string? Title { get { return GetStringValue ("title"); } } - /// To be added. - /// To be added. - /// To be added. + /// The track number. public string? TrackNumber { get { return GetStringValue ("track number"); } } - /// To be added. - /// To be added. - /// To be added. + /// The year. public string? Year { get { return GetStringValue ("year"); @@ -2641,18 +2540,19 @@ public string? Year { delegate long GetSizeProc (IntPtr clientData); delegate int SetSizeProc (IntPtr clientData, long size); - /// A derived class from AudioFile that exposes virtual methods that can be hooked into (for reading and writing) - /// - /// - /// AudioSource is an abstract class that derives from AudioFile that allows developers to hook up into the reading and writing stages of the AudioFile. This can be used for example to read from an in-memory audio file, or to write to an in-memory buffer. - /// - /// - /// When you write data into the AudioSource using any of the methods from AudioFile, instead of writing the encoded data into a file, the data is sent to the Read abstract method. - /// - /// - /// To use this class, you must create a class that derives from AudioSource and override the Read, Write methods and the Size property. - /// - /// + /// A derived class from that exposes virtual methods that can be hooked into (for reading and writing). + /// + /// + /// is an abstract class that derives from that allows developers to hook up into the reading and writing stages of the . + /// This can be used for example to read from an in-memory audio file, or to write to an in-memory buffer. + /// + /// + /// When you write data into the using any of the methods from , instead of writing the encoded data into a file, the data is sent to the abstract method. + /// + /// + /// To use this class, you must create a class that derives from and override the , methods and the property. + /// + /// [SupportedOSPlatform ("ios")] [SupportedOSPlatform ("maccatalyst")] [SupportedOSPlatform ("macos")] @@ -2671,13 +2571,13 @@ static unsafe int SourceRead (IntPtr clientData, long inPosition, int requestCou return result; } + /// Callback invoked to read encoded audio data. /// Position in the audio stream that the data should be read from. - /// Number of bytes to read. - /// Pointer to the buffer where the data should be stored. - /// On return, set this value to the number of bytes actually read. - /// Callback invoked to read encoded audio data. - /// true on success, false on failure. - /// This method is called by the AudioSource when more data is requested. + /// Number of bytes to read. + /// Pointer to the buffer where the data should be stored. + /// On return, set this value to the number of bytes actually read. + /// true on success, false on failure. + /// This method is called by the when more data is requested. public abstract bool Read (long position, int requestCount, IntPtr buffer, out int actualCount); [UnmanagedCallersOnly] @@ -2690,13 +2590,13 @@ static unsafe int SourceWrite (IntPtr clientData, long position, int requestCoun *actualCount = localCount; return result; } + /// Callback used to write audio data into the audio stream. /// Position where the data should be stored. - /// Number of bytes to write. - /// Pointer to the buffer that contains the data to be written. - /// Set this value to indicate the number of bytes actually written. - /// Callback used to write audio data into the audio stream. - /// True on success, false on failure. - /// This method is called by the AudioSource when it has encoded the data and it need to write it out. + /// Number of bytes to write. + /// Pointer to the buffer that contains the data to be written. + /// Set this value to indicate the number of bytes actually written. + /// True on success, false on failure. + /// This method is called by the when it has encoded the data and it need to write it out. public abstract bool Write (long position, int requestCount, IntPtr buffer, out int actualCount); [UnmanagedCallersOnly] @@ -2718,11 +2618,12 @@ static int SourceSetSize (IntPtr clientData, long size) return 0; } /// Used to set or get the size of the audio stream. - /// The size of the file. - /// If the AudioSource is created in reading mode, this method should return the size of the audio data. If the AudioSource is created to write data, this method is invoked to set the audio file size. + /// The size of the file. + /// If the is created in reading mode, this method should return the size of the audio data. If the is created to write data, this method is invoked to set the audio file size. public abstract long Size { get; set; } - /// + /// Releases the resources used by the object. + /// If set to , the method is invoked directly and will dispose managed and unmanaged resources; If set to the method is being called by the garbage collector finalizer and should only release unmanaged resources. protected override void Dispose (bool disposing) { base.Dispose (disposing); @@ -2731,7 +2632,7 @@ protected override void Dispose (bool disposing) } [DllImport (Constants.AudioToolboxLibrary)] - extern unsafe static OSStatus AudioFileInitializeWithCallbacks ( + extern unsafe static AudioFileError AudioFileInitializeWithCallbacks ( IntPtr inClientData, delegate* unmanaged inReadFunc, delegate* unmanaged inWriteFunc, @@ -2739,33 +2640,30 @@ extern unsafe static OSStatus AudioFileInitializeWithCallbacks ( delegate* unmanaged inSetSizeFunc, AudioFileType inFileType, AudioStreamBasicDescription* format, uint flags, IntPtr* id); - /// To be added. - /// To be added. - /// To be added. - /// To be added. + /// Create a new instance, with the specified file type and format. + /// The file type for the new audio source. + /// The audio format for the new audio source. public AudioSource (AudioFileType inFileType, AudioStreamBasicDescription format) { Initialize (inFileType, format); } /// Constructor used when creating subclasses - /// - /// This constructor is provided as a convenience for - /// developers that need to decouple the creation of the - /// AudioSource from starting the read and write process. Once you have created this object, you need to invoke the method to complete the setup. - /// + /// + /// This constructor is provided as a convenience for developers that need to decouple the creation of the from starting the read and write process. + /// Once you have created this object, you need to invoke the method to complete the setup. + /// public AudioSource () { } - /// To be added. - /// To be added. - /// To be added. - /// To be added. + /// Initialize the audio source with the specified file type and format. + /// The file type for the new audio source. + /// The audio format for the new audio source. protected void Initialize (AudioFileType inFileType, AudioStreamBasicDescription format) { gch = GCHandle.Alloc (this); - int code = 0; + AudioFileError code; IntPtr handle = IntPtr.Zero; unsafe { code = AudioFileInitializeWithCallbacks (GCHandle.ToIntPtr (gch), &SourceRead, &SourceWrite, &SourceGetSize, &SourceSetSize, inFileType, &format, 0, &handle); @@ -2774,11 +2672,11 @@ protected void Initialize (AudioFileType inFileType, AudioStreamBasicDescription InitializeHandle (handle); return; } - throw new Exception (String.Format ("Unable to create AudioSource, code: 0x{0:x}", code)); + throw new Exception (String.Format ("Unable to create AudioSource: {0}", code)); } [DllImport (Constants.AudioToolboxLibrary)] - extern static unsafe int AudioFileOpenWithCallbacks ( + extern static unsafe AudioFileError AudioFileOpenWithCallbacks ( IntPtr inClientData, delegate* unmanaged inReadFunc, delegate* unmanaged inWriteFunc, @@ -2786,21 +2684,19 @@ extern static unsafe int AudioFileOpenWithCallbacks ( delegate* unmanaged inSetSizeFunc, AudioFileType inFileTypeHint, IntPtr* outAudioFile); - /// To be added. - /// To be added. - /// To be added. + /// Create a new instance, with the specified file type. + /// The file type for the new audio source. public AudioSource (AudioFileType fileTypeHint) { Open (fileTypeHint); } - /// To be added. - /// To be added. - /// To be added. + /// Open the audio source for reading and/or writing. + /// The file type for the audio source. protected void Open (AudioFileType fileTypeHint) { gch = GCHandle.Alloc (this); - int code = 0; + AudioFileError code; IntPtr handle = IntPtr.Zero; unsafe { code = AudioFileOpenWithCallbacks (GCHandle.ToIntPtr (gch), &SourceRead, &SourceWrite, &SourceGetSize, &SourceSetSize, fileTypeHint, &handle); @@ -2809,7 +2705,7 @@ protected void Open (AudioFileType fileTypeHint) InitializeHandle (handle); return; } - throw new Exception (String.Format ("Unable to create AudioSource, code: 0x{0:x}", code)); + throw new Exception (String.Format ("Unable to create AudioSource: {0}", code)); } } } diff --git a/tests/monotouch-test/AudioToolbox/AudioConverterTest.cs b/tests/monotouch-test/AudioToolbox/AudioConverterTest.cs index 60b17a43eafa..e51b717136c0 100644 --- a/tests/monotouch-test/AudioToolbox/AudioConverterTest.cs +++ b/tests/monotouch-test/AudioToolbox/AudioConverterTest.cs @@ -2,6 +2,7 @@ #if __IOS__ || __MACOS__ using System; +using System.Diagnostics; using System.Drawing; using System.IO; using System.Linq; @@ -59,21 +60,33 @@ public void PrepareWithCallback () } } + void DoWithTemporaryDirectory (Action action) + { + var temporaryDirectory = Path.Combine (NSFileManager.TemporaryDirectory, "monotouch-test", Process.GetCurrentProcess ().Id.ToString ()); + try { + Directory.CreateDirectory (temporaryDirectory); + action (temporaryDirectory); + } finally { + Directory.Delete (temporaryDirectory, true); + } + } + [Test] public void CreateWithOptions () { TestRuntime.AssertXcodeVersion (16, 0); var sourcePath = Path.Combine (NSBundle.MainBundle.ResourcePath, "Hand.wav"); - var paths = NSSearchPath.GetDirectories (NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomain.User); - // Convert once - var output1 = Path.Combine (paths [0], "outputOptions1.caf"); - Convert (sourcePath, output1, AudioFormatType.AppleLossless, options: AudioConverterOptions.None); + DoWithTemporaryDirectory ((temporaryDirectory) => { + // Convert once + var output1 = Path.Combine (temporaryDirectory, "outputOptions1.caf"); + Convert (sourcePath, output1, AudioFormatType.AppleLossless, options: AudioConverterOptions.None); - // Convert converted output - var output2 = Path.Combine (paths [0], "outputOptions2.wav"); - Convert (output1, output2, AudioFormatType.LinearPCM, options: AudioConverterOptions.None); + // Convert converted output + var output2 = Path.Combine (temporaryDirectory, "outputOptions2.wav"); + Convert (output1, output2, AudioFormatType.LinearPCM, options: AudioConverterOptions.None); + }); } [Test] @@ -82,15 +95,16 @@ public void Convert () TestRuntime.AssertXcodeVersion (9, 0); var sourcePath = Path.Combine (NSBundle.MainBundle.ResourcePath, "Hand.wav"); - var paths = NSSearchPath.GetDirectories (NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomain.User); - // Convert once - var output1 = Path.Combine (paths [0], "output1.caf"); - Convert (sourcePath, output1, AudioFormatType.AppleLossless); + DoWithTemporaryDirectory ((temporaryDirectory) => { + // Convert once + var output1 = Path.Combine (temporaryDirectory, "output1.caf"); + Convert (sourcePath, output1, AudioFormatType.AppleLossless); - // Convert converted output - var output2 = Path.Combine (paths [0], "output2.wav"); - Convert (output1, output2, AudioFormatType.LinearPCM); + // Convert converted output + var output2 = Path.Combine (temporaryDirectory, "output2.wav"); + Convert (output1, output2, AudioFormatType.LinearPCM); + }); } void Convert (string sourceFilePath, string destinationFilePath, AudioFormatType outputFormatType, int? sampleRate = null, AudioConverterOptions? options = null) @@ -155,7 +169,9 @@ void Convert (string sourceFilePath, string destinationFilePath, AudioFormatType dstFormat = converter.CurrentOutputStreamDescription; // create the destination file - using var destinationFile = AudioFile.Create (destinationUrl, AudioFileType.CAF, dstFormat, AudioFileFlags.EraseFlags); + using var destinationFile = AudioFile.Create (destinationUrl, AudioFileType.CAF, dstFormat, AudioFileFlags.EraseFlags, out var audioFileStatus); + Assert.That (audioFileStatus, Is.EqualTo (AudioFileError.Success), $"AudioFile.Create ({destinationUrl}"); + Assert.That (destinationFile, Is.Not.Null, $"destinationFile: {destinationUrl}"); // set up source buffers and data proc info struct afio.SourceFile = sourceFile; From 7dde9f1fd295004017159c5a36a2bf46ac343ef7 Mon Sep 17 00:00:00 2001 From: Rolf Bjarne Kvinge Date: Fri, 5 Sep 2025 07:49:50 +0200 Subject: [PATCH 2/2] Update known docs. --- tests/cecil-tests/Documentation.KnownFailures.txt | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/cecil-tests/Documentation.KnownFailures.txt b/tests/cecil-tests/Documentation.KnownFailures.txt index ced8c624907a..a1c9a87bea41 100644 --- a/tests/cecil-tests/Documentation.KnownFailures.txt +++ b/tests/cecil-tests/Documentation.KnownFailures.txt @@ -17878,9 +17878,6 @@ P:ARKit.ARVideoFormat.IsVideoHdrSupported P:ARKit.ARWorldTrackingConfiguration.CollaborationEnabled P:ARKit.IARSessionProviding.Session P:AudioToolbox.AudioBuffers.Item(System.Int32) -P:AudioToolbox.AudioFileMarkerList.Item(System.Int32) -P:AudioToolbox.AudioFileRegion.Item(System.Int32) -P:AudioToolbox.AudioFileRegionList.Item(System.Int32) P:AudioToolbox.AudioPacketDependencyInfoTranslation.IsIndependentlyDecodable P:AudioToolbox.SystemSound.SoundId P:AudioUnit.AUAudioUnit.IsLoadedInProcess