SoundIO.cs 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Runtime.InteropServices;
  4. namespace SoundIOSharp
  5. {
  6. public class SoundIO : IDisposable
  7. {
  8. Pointer<SoundIo> handle;
  9. public SoundIO ()
  10. {
  11. handle = Natives.soundio_create ();
  12. }
  13. internal SoundIO (Pointer<SoundIo> handle)
  14. {
  15. this.handle = handle;
  16. }
  17. public void Dispose ()
  18. {
  19. foreach (var h in allocated_hglobals)
  20. Marshal.FreeHGlobal (h);
  21. Natives.soundio_destroy (handle);
  22. }
  23. // Equality (based on handle)
  24. public override bool Equals (object other)
  25. {
  26. var d = other as SoundIO;
  27. return d != null && this.handle == d.handle;
  28. }
  29. public override int GetHashCode ()
  30. {
  31. return (int) (IntPtr) handle;
  32. }
  33. public static bool operator == (SoundIO obj1, SoundIO obj2)
  34. {
  35. return (object)obj1 == null ? (object)obj2 == null : obj1.Equals (obj2);
  36. }
  37. public static bool operator != (SoundIO obj1, SoundIO obj2)
  38. {
  39. return (object)obj1 == null ? (object)obj2 != null : !obj1.Equals (obj2);
  40. }
  41. // fields
  42. // FIXME: this should be taken care in more centralized/decent manner... we don't want to write
  43. // this kind of code anywhere we need string marshaling.
  44. List<IntPtr> allocated_hglobals = new List<IntPtr> ();
  45. public string ApplicationName {
  46. get { return Marshal.PtrToStringAnsi (Marshal.ReadIntPtr (handle, app_name_offset)); }
  47. set {
  48. unsafe {
  49. var existing = Marshal.ReadIntPtr (handle, app_name_offset);
  50. if (allocated_hglobals.Contains (existing)) {
  51. allocated_hglobals.Remove (existing);
  52. Marshal.FreeHGlobal (existing);
  53. }
  54. var ptr = Marshal.StringToHGlobalAnsi (value);
  55. Marshal.WriteIntPtr (handle, app_name_offset, ptr);
  56. allocated_hglobals.Add (ptr);
  57. }
  58. }
  59. }
  60. static readonly int app_name_offset = (int)Marshal.OffsetOf<SoundIo> ("app_name");
  61. public SoundIOBackend CurrentBackend {
  62. get { return (SoundIOBackend) Marshal.ReadInt32 (handle, current_backend_offset); }
  63. }
  64. static readonly int current_backend_offset = (int)Marshal.OffsetOf<SoundIo> ("current_backend");
  65. // emit_rtprio_warning
  66. public Action EmitRealtimePriorityWarning {
  67. get { return emit_rtprio_warning; }
  68. set {
  69. emit_rtprio_warning = value;
  70. var ptr = Marshal.GetFunctionPointerForDelegate (on_devices_change);
  71. Marshal.WriteIntPtr (handle, emit_rtprio_warning_offset, ptr);
  72. }
  73. }
  74. static readonly int emit_rtprio_warning_offset = (int)Marshal.OffsetOf<SoundIo> ("emit_rtprio_warning");
  75. Action emit_rtprio_warning;
  76. // jack_error_callback
  77. public Action<string> JackErrorCallback {
  78. get { return jack_error_callback; }
  79. set {
  80. jack_error_callback = value;
  81. if (value == null)
  82. jack_error_callback = null;
  83. else
  84. jack_error_callback_native = msg => jack_error_callback (msg);
  85. var ptr = Marshal.GetFunctionPointerForDelegate (jack_error_callback_native);
  86. Marshal.WriteIntPtr (handle, jack_error_callback_offset, ptr);
  87. }
  88. }
  89. static readonly int jack_error_callback_offset = (int)Marshal.OffsetOf<SoundIo> ("jack_error_callback");
  90. Action<string> jack_error_callback;
  91. delegate void jack_error_delegate (string message);
  92. jack_error_delegate jack_error_callback_native;
  93. // jack_info_callback
  94. public Action<string> JackInfoCallback {
  95. get { return jack_info_callback; }
  96. set {
  97. jack_info_callback = value;
  98. if (value == null)
  99. jack_info_callback = null;
  100. else
  101. jack_info_callback_native = msg => jack_info_callback (msg);
  102. var ptr = Marshal.GetFunctionPointerForDelegate (jack_info_callback_native);
  103. Marshal.WriteIntPtr (handle, jack_info_callback_offset, ptr);
  104. }
  105. }
  106. static readonly int jack_info_callback_offset = (int)Marshal.OffsetOf<SoundIo> ("jack_info_callback");
  107. Action<string> jack_info_callback;
  108. delegate void jack_info_delegate (string message);
  109. jack_info_delegate jack_info_callback_native;
  110. // on_backend_disconnect
  111. public Action<int> OnBackendDisconnect {
  112. get { return on_backend_disconnect; }
  113. set {
  114. on_backend_disconnect = value;
  115. if (value == null)
  116. on_backend_disconnect_native = null;
  117. else
  118. on_backend_disconnect_native = (sio, err) => on_backend_disconnect (err);
  119. var ptr = Marshal.GetFunctionPointerForDelegate (on_backend_disconnect_native);
  120. Marshal.WriteIntPtr (handle, on_backend_disconnect_offset, ptr);
  121. }
  122. }
  123. static readonly int on_backend_disconnect_offset = (int)Marshal.OffsetOf<SoundIo> ("on_backend_disconnect");
  124. Action<int> on_backend_disconnect;
  125. delegate void on_backend_disconnect_delegate (IntPtr handle, int errorCode);
  126. on_backend_disconnect_delegate on_backend_disconnect_native;
  127. // on_devices_change
  128. public Action OnDevicesChange {
  129. get { return on_devices_change; }
  130. set {
  131. on_devices_change = value;
  132. if (value == null)
  133. on_devices_change_native = null;
  134. else
  135. on_devices_change_native = sio => on_devices_change ();
  136. var ptr = Marshal.GetFunctionPointerForDelegate (on_devices_change_native);
  137. Marshal.WriteIntPtr (handle, on_devices_change_offset, ptr);
  138. }
  139. }
  140. static readonly int on_devices_change_offset = (int)Marshal.OffsetOf<SoundIo> ("on_devices_change");
  141. Action on_devices_change;
  142. delegate void on_devices_change_delegate (IntPtr handle);
  143. on_devices_change_delegate on_devices_change_native;
  144. // on_events_signal
  145. public Action OnEventsSignal {
  146. get { return on_events_signal; }
  147. set {
  148. on_events_signal = value;
  149. if (value == null)
  150. on_events_signal_native = null;
  151. else
  152. on_events_signal_native = sio => on_events_signal ();
  153. var ptr = Marshal.GetFunctionPointerForDelegate (on_events_signal_native);
  154. Marshal.WriteIntPtr (handle, on_events_signal_offset, ptr);
  155. }
  156. }
  157. static readonly int on_events_signal_offset = (int)Marshal.OffsetOf<SoundIo> ("on_events_signal");
  158. Action on_events_signal;
  159. delegate void on_events_signal_delegate (IntPtr handle);
  160. on_events_signal_delegate on_events_signal_native;
  161. // functions
  162. public int BackendCount {
  163. get { return Natives.soundio_backend_count (handle); }
  164. }
  165. public int InputDeviceCount {
  166. get { return Natives.soundio_input_device_count (handle); }
  167. }
  168. public int OutputDeviceCount {
  169. get { return Natives.soundio_output_device_count (handle); }
  170. }
  171. public int DefaultInputDeviceIndex {
  172. get { return Natives.soundio_default_input_device_index (handle); }
  173. }
  174. public int DefaultOutputDeviceIndex {
  175. get { return Natives.soundio_default_output_device_index (handle); }
  176. }
  177. public SoundIOBackend GetBackend (int index)
  178. {
  179. return (SoundIOBackend) Natives.soundio_get_backend (handle, index);
  180. }
  181. public SoundIODevice GetInputDevice (int index)
  182. {
  183. return new SoundIODevice (Natives.soundio_get_input_device (handle, index));
  184. }
  185. public SoundIODevice GetOutputDevice (int index)
  186. {
  187. return new SoundIODevice (Natives.soundio_get_output_device (handle, index));
  188. }
  189. public void Connect ()
  190. {
  191. var ret = (SoundIoError) Natives.soundio_connect (handle);
  192. if (ret != SoundIoError.SoundIoErrorNone)
  193. throw new SoundIOException (ret);
  194. }
  195. public void ConnectBackend (SoundIOBackend backend)
  196. {
  197. var ret = (SoundIoError) Natives.soundio_connect_backend (handle, (SoundIoBackend) backend);
  198. if (ret != SoundIoError.SoundIoErrorNone)
  199. throw new SoundIOException (ret);
  200. }
  201. public void Disconnect ()
  202. {
  203. Natives.soundio_disconnect (handle);
  204. }
  205. public void FlushEvents ()
  206. {
  207. Natives.soundio_flush_events (handle);
  208. }
  209. public void WaitEvents ()
  210. {
  211. Natives.soundio_wait_events (handle);
  212. }
  213. public void Wakeup ()
  214. {
  215. Natives.soundio_wakeup (handle);
  216. }
  217. public void ForceDeviceScan ()
  218. {
  219. Natives.soundio_force_device_scan (handle);
  220. }
  221. public SoundIORingBuffer CreateRingBuffer (int capacity)
  222. {
  223. return new SoundIORingBuffer (Natives.soundio_ring_buffer_create (handle, capacity));
  224. }
  225. // static methods
  226. public static string VersionString {
  227. get { return Marshal.PtrToStringAnsi (Natives.soundio_version_string ()); }
  228. }
  229. public static int VersionMajor {
  230. get { return Natives.soundio_version_major (); }
  231. }
  232. public static int VersionMinor {
  233. get { return Natives.soundio_version_minor (); }
  234. }
  235. public static int VersionPatch {
  236. get { return Natives.soundio_version_patch (); }
  237. }
  238. public static string GetBackendName (SoundIOBackend backend)
  239. {
  240. return Marshal.PtrToStringAnsi (Natives.soundio_backend_name ((SoundIoBackend) backend));
  241. }
  242. public static bool HaveBackend (SoundIOBackend backend)
  243. {
  244. return Natives.soundio_have_backend ((SoundIoBackend) backend);
  245. }
  246. public static int GetBytesPerSample (SoundIOFormat format)
  247. {
  248. return Natives.soundio_get_bytes_per_sample ((SoundIoFormat) format);
  249. }
  250. public static int GetBytesPerFrame (SoundIOFormat format, int channelCount)
  251. {
  252. return Natives.soundio_get_bytes_per_frame ((SoundIoFormat) format, channelCount);
  253. }
  254. public static int GetBytesPerSecond (SoundIOFormat format, int channelCount, int sampleRate)
  255. {
  256. return Natives.soundio_get_bytes_per_second ((SoundIoFormat) format, channelCount, sampleRate);
  257. }
  258. public static string GetSoundFormatName (SoundIOFormat format)
  259. {
  260. return Marshal.PtrToStringAnsi (Natives.soundio_format_string ((SoundIoFormat) format));
  261. }
  262. }
  263. }