299 lines
12 KiB
C#
299 lines
12 KiB
C#
/***
|
|
|
|
MIT License
|
|
|
|
Copyright (c) 2018 Nathan Glover
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
of this software and associated documentation files (the "Software"), to deal
|
|
in the Software without restriction, including without limitation the rights
|
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
copies of the Software, and to permit persons to whom the Software is
|
|
furnished to do so, subject to the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be included in all
|
|
copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
SOFTWARE.
|
|
|
|
****************
|
|
|
|
Further modified for use in Barotrauma.
|
|
Original source code at https://github.com/NathanielGlover/OpenAL.NETCore/
|
|
|
|
***/
|
|
|
|
using System;
|
|
using System.Runtime.InteropServices;
|
|
using System.Collections.Generic;
|
|
using System.Text;
|
|
|
|
namespace OpenAL
|
|
{
|
|
public class Alc
|
|
{
|
|
#if OSX
|
|
public const string OpenAlDll = "/System/Library/Frameworks/OpenAL.framework/OpenAL";
|
|
#elif LINUX
|
|
public const string OpenAlDll = "libopenal.so.1";
|
|
#elif WINDOWS
|
|
public const string OpenAlDll = "soft_oal_x64.dll";
|
|
#endif
|
|
|
|
public delegate void ErrorReasonCallback(string str);
|
|
|
|
#if WINDOWS
|
|
[DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alcSetErrorReasonCallback")]
|
|
private static extern void SetErrorReasonCallback(IntPtr callback);
|
|
|
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
private delegate void ErrorReasonCallbackInternal(IntPtr cstr);
|
|
|
|
private static ErrorReasonCallbackInternal CurrentErrorReasonCallback;
|
|
private static IntPtr CurrentErrorReasonCallbackPtr;
|
|
|
|
public static void SetErrorReasonCallback(ErrorReasonCallback callback)
|
|
{
|
|
CurrentErrorReasonCallback = (IntPtr cstr) =>
|
|
{
|
|
int strLen = 0;
|
|
while (Marshal.ReadByte(cstr, strLen) != '\0') { strLen++; }
|
|
byte[] bytes = new byte[strLen];
|
|
Marshal.Copy(cstr, bytes, 0, strLen);
|
|
string csStr = Encoding.UTF8.GetString(bytes);
|
|
|
|
callback?.Invoke(csStr);
|
|
};
|
|
|
|
CurrentErrorReasonCallbackPtr = Marshal.GetFunctionPointerForDelegate(CurrentErrorReasonCallback);
|
|
SetErrorReasonCallback(CurrentErrorReasonCallbackPtr);
|
|
}
|
|
#else
|
|
public static void SetErrorReasonCallback(ErrorReasonCallback callback)
|
|
{
|
|
//FIXME: not implemented on macOS and Linux
|
|
}
|
|
#endif
|
|
|
|
#region Enum
|
|
|
|
public const int False = 0;
|
|
public const int True = 1;
|
|
public const int Frequency = 0x1007;
|
|
public const int Refresh = 0x1008;
|
|
public const int Sync = 0x1009;
|
|
public const int MonoSources = 0x1010;
|
|
public const int StereoSources = 0x1011;
|
|
public const int NoError = False;
|
|
public const int InvalidDevice = 0xA001;
|
|
public const int InvalidContext = 0xA002;
|
|
public const int InvalidEnum = 0xA003;
|
|
public const int InvalidValue = 0xA004;
|
|
public const int OutOfMemory = 0xA005;
|
|
public const int DefaultDeviceSpecifier = 0x1004;
|
|
public const int DeviceSpecifier = 0x1005;
|
|
public const int Extensions = 0x1006;
|
|
public const int MajorVersion = 0x1000;
|
|
public const int MinorVersion = 0x1001;
|
|
public const int AttributesSize = 0x1002;
|
|
public const int AllAttributes = 0x1003;
|
|
public const int DefaultAllDevicesSpecifier = 0x1012;
|
|
public const int AllDevicesSpecifier = 0x1013;
|
|
public const int CaptureDeviceSpecifier = 0x310;
|
|
public const int CaptureDefaultDeviceSpecifier = 0x311;
|
|
public const int EnumCaptureSamples = 0x312;
|
|
public const int EnumConnected = 0x313;
|
|
|
|
|
|
public const int OutputDevicesSpecifier =
|
|
#if OSX
|
|
DeviceSpecifier;
|
|
#else
|
|
AllDevicesSpecifier;
|
|
#endif
|
|
|
|
#endregion
|
|
|
|
#region Context Management Functions
|
|
|
|
[DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alcCreateContext")]
|
|
private static extern IntPtr _CreateContext(IntPtr device, IntPtr attrlist);
|
|
|
|
public static IntPtr CreateContext(IntPtr device, int[] attrList)
|
|
{
|
|
GCHandle handle = GCHandle.Alloc(attrList, GCHandleType.Pinned);
|
|
IntPtr retVal = _CreateContext(device, handle.AddrOfPinnedObject());
|
|
handle.Free();
|
|
return retVal;
|
|
}
|
|
|
|
[DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alcMakeContextCurrent")]
|
|
public static extern bool MakeContextCurrent(IntPtr context);
|
|
|
|
[DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alcProcessContext")]
|
|
public static extern void ProcessContext(IntPtr context);
|
|
|
|
[DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alcSuspendContext")]
|
|
public static extern void SuspendContext(IntPtr context);
|
|
|
|
[DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alcDestroyContext")]
|
|
public static extern void DestroyContext(IntPtr context);
|
|
|
|
[DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alcGetCurrentContext")]
|
|
public static extern IntPtr GetCurrentContext();
|
|
|
|
[DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alcGetContextsDevice")]
|
|
public static extern IntPtr GetContextsDevice(IntPtr context);
|
|
|
|
[DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alcOpenDevice")]
|
|
private static extern IntPtr OpenDevice(IntPtr deviceName);
|
|
|
|
public static IntPtr OpenDevice(string deviceName)
|
|
{
|
|
if (deviceName == null)
|
|
{
|
|
return OpenDevice(IntPtr.Zero);
|
|
}
|
|
|
|
byte[] devicenameBytes = Encoding.UTF8.GetBytes(deviceName + "\0");
|
|
GCHandle devicenameHandle = GCHandle.Alloc(devicenameBytes, GCHandleType.Pinned);
|
|
IntPtr retVal = OpenDevice(devicenameHandle.AddrOfPinnedObject());
|
|
devicenameHandle.Free();
|
|
|
|
return retVal;
|
|
}
|
|
|
|
[DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alcCloseDevice")]
|
|
public static extern bool CloseDevice(IntPtr device);
|
|
|
|
[DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alcGetError")]
|
|
public static extern int GetError(IntPtr device);
|
|
|
|
public static string GetErrorString(int errorCode)
|
|
{
|
|
switch (errorCode)
|
|
{
|
|
case NoError:
|
|
return "No error";
|
|
case InvalidContext:
|
|
return "Invalid context";
|
|
case InvalidDevice:
|
|
return "Invalid device";
|
|
case InvalidEnum:
|
|
return "Invalid enum";
|
|
case InvalidValue:
|
|
return "Invalid value";
|
|
case OutOfMemory:
|
|
return "Out of memory";
|
|
default:
|
|
return "Unknown error";
|
|
}
|
|
}
|
|
|
|
[DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alcIsExtensionPresent")]
|
|
public static extern bool IsExtensionPresent(IntPtr device, string extname);
|
|
|
|
[DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alcGetProcAddress")]
|
|
public static extern IntPtr GetProcAddress(IntPtr device, string funcname);
|
|
|
|
[DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alcGetEnumValue")]
|
|
public static extern int GetEnumValue(IntPtr device, string enumname);
|
|
|
|
#endregion
|
|
|
|
#region Query Functions
|
|
|
|
[DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alcGetString")]
|
|
private static extern IntPtr _GetString(IntPtr device, int param);
|
|
|
|
public static string GetString(IntPtr device, int param)
|
|
{
|
|
IntPtr strPtr = _GetString(device, param);
|
|
int strLen = 0;
|
|
while (Marshal.ReadByte(strPtr,strLen)!='\0') { strLen++; }
|
|
byte[] bytes = new byte[strLen];
|
|
Marshal.Copy(strPtr, bytes, 0, strLen);
|
|
return Encoding.UTF8.GetString(bytes);
|
|
}
|
|
|
|
public static IReadOnlyList<string> GetStringList(IntPtr device, int param)
|
|
{
|
|
List<string> retVal = new List<string>();
|
|
IntPtr strPtr = _GetString(device, param);
|
|
if (strPtr == IntPtr.Zero) { return retVal; }
|
|
int strStart = 0;
|
|
int strEnd = 0;
|
|
byte currChar = Marshal.ReadByte(strPtr, strEnd);
|
|
if (currChar == '\0') { return retVal; }
|
|
byte prevChar = 255;
|
|
while (true)
|
|
{
|
|
strEnd++;
|
|
prevChar = currChar;
|
|
currChar = Marshal.ReadByte(strPtr, strEnd);
|
|
|
|
if (currChar == '\0')
|
|
{
|
|
if (prevChar == '\0')
|
|
{
|
|
break;
|
|
}
|
|
byte[] bytes = new byte[strEnd-strStart];
|
|
Marshal.Copy(strPtr+strStart, bytes, 0, strEnd - strStart);
|
|
retVal.Add(Encoding.UTF8.GetString(bytes));
|
|
strStart = strEnd+1;
|
|
}
|
|
}
|
|
return retVal;
|
|
}
|
|
|
|
[DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alcGetIntegerv")]
|
|
public static extern void GetIntegerv(IntPtr device, int param, int size, IntPtr data);
|
|
|
|
public static void GetInteger(IntPtr device, int param, out int data)
|
|
{
|
|
int[] dataArr = new int[1];
|
|
GCHandle handle = GCHandle.Alloc(dataArr,GCHandleType.Pinned);
|
|
GetIntegerv(device, param, 1, handle.AddrOfPinnedObject());
|
|
handle.Free();
|
|
data = dataArr[0];
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Capture Functions
|
|
|
|
[DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alcCaptureOpenDevice")]
|
|
private static extern IntPtr CaptureOpenDevice(IntPtr devicename, uint frequency, int format, int buffersize);
|
|
|
|
public static IntPtr CaptureOpenDevice(string devicename, uint frequency, int format, int buffersize)
|
|
{
|
|
byte[] devicenameBytes = Encoding.UTF8.GetBytes(devicename + "\0");
|
|
GCHandle devicenameHandle = GCHandle.Alloc(devicenameBytes, GCHandleType.Pinned);
|
|
IntPtr retVal = CaptureOpenDevice(devicenameHandle.AddrOfPinnedObject(), frequency, format, buffersize);
|
|
devicenameHandle.Free();
|
|
return retVal;
|
|
}
|
|
|
|
[DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alcCaptureCloseDevice")]
|
|
public static extern bool CaptureCloseDevice(IntPtr device);
|
|
|
|
[DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alcCaptureStart")]
|
|
public static extern void CaptureStart(IntPtr device);
|
|
|
|
[DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alcCaptureStop")]
|
|
public static extern void CaptureStop(IntPtr device);
|
|
|
|
[DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alcCaptureSamples")]
|
|
public static extern void CaptureSamples(IntPtr device, IntPtr buffer, int samples);
|
|
|
|
#endregion
|
|
}
|
|
}
|