Skip to content

Commit

Permalink
[AudioToolbox] Use unsafe code to marshal in/out arrays. Fixes #xamar…
Browse files Browse the repository at this point in the history
…in/maccore@2537. (#13694)

Arrays are by default only marshaled to P/Invokes, any changes done to the array
in native code are not copied back to managed memory.

Ref: https://docs.microsoft.com/en-us/dotnet/framework/interop/marshaling-different-types-of-arrays

However, broken code tend to work just fine, because the runtime usually just passes
a pointer to the managed memory to the P/Invoke. This is fast (no need to copy memory
around), but it also has the side effect that any changes to the memory during execution
of the P/Invoke is observed in managed code as well.

For some reason the MonoTouchFixtures.AudioToolbox.AudioConverterTest test runs into
a scenario where this isn't the case, and the test ends up hanging.

So fix it by making the P/Invoke take a pointer to the AudioStreamPacketDescription
array instead of the array itself, and we explicitly pass it a pointer to the managed
memory of the array. This way we'll see any changes to the array in managed code.

Fixes xamarin/maccore#2537.
  • Loading branch information
rolfbjarne authored Jan 13, 2022
1 parent f269d03 commit 621ec3f
Showing 1 changed file with 9 additions and 3 deletions.
12 changes: 9 additions & 3 deletions src/AudioToolbox/AudioFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -794,7 +794,7 @@ public int Write (long startingByte, byte [] buffer, int offset, int count, bool
[DllImport (Constants.AudioToolboxLibrary)]
unsafe extern static OSStatus AudioFileReadPacketData (
AudioFileID audioFile, [MarshalAs (UnmanagedType.I1)] bool useCache, ref int numBytes,
AudioStreamPacketDescription [] packetDescriptions, long inStartingPacket, ref int numPackets, IntPtr outBuffer);
AudioStreamPacketDescription* packetDescriptions, long inStartingPacket, ref int numPackets, IntPtr outBuffer);

public AudioStreamPacketDescription []? ReadPacketData (long inStartingPacket, int nPackets, byte [] buffer)
{
Expand Down Expand Up @@ -898,7 +898,10 @@ unsafe extern static OSStatus AudioFileReadPacketData (

unsafe AudioStreamPacketDescription []? RealReadPacketData (bool useCache, long inStartingPacket, ref int nPackets, IntPtr buffer, ref int count, out AudioFileError error, AudioStreamPacketDescription[] descriptions)
{
var r = AudioFileReadPacketData (Handle, useCache, ref count, descriptions, inStartingPacket, ref nPackets, buffer);
OSStatus r;
fixed (AudioStreamPacketDescription* pdesc = &descriptions [0]) {
r = AudioFileReadPacketData (Handle, useCache, ref count, pdesc, inStartingPacket, ref nPackets, buffer);
}

error = (AudioFileError)r;

Expand Down Expand Up @@ -957,7 +960,10 @@ unsafe extern static OSStatus AudioFileReadPacketData (
{
var descriptions = new AudioStreamPacketDescription [nPackets];
fixed (byte *bop = &buffer [offset]){
var r = AudioFileReadPacketData (Handle, useCache, ref count, descriptions, inStartingPacket, ref nPackets, (IntPtr) bop);
OSStatus r;
fixed (AudioStreamPacketDescription* pdesc = &descriptions [0]) {
r = AudioFileReadPacketData (Handle, useCache, ref count, pdesc, inStartingPacket, ref nPackets, (IntPtr) bop);
}
error = (AudioFileError)r;
if (r == (int) AudioFileError.EndOfFile) {
if (count == 0)
Expand Down

0 comments on commit 621ec3f

Please sign in to comment.