diff --git a/NOTICE.md b/NOTICE.md
index 516e5677f2..aeb97eefa7 100644
--- a/NOTICE.md
+++ b/NOTICE.md
@@ -34,12 +34,9 @@ public domain. For details, see [project/lib/lzma/](project/lzma).
This product bundles mbedTLS 2.6.0, which is available under an
"Apache 2.0" license. For details, see [project/lib/mbedtls/](project/lib).
-This product bundles OpenAL-Soft 1.19.0, which is available under an
+This product bundles OpenAL-Soft 1.25.1, which is available under an
"LGPLv2" license. For details, see [project/lib/openal/](project/lib).
-_OpenAL-Soft is only included in dynamically-linked builds, it is excluded
-from Lime static builds in order to preserve Lime's permissive nature._
-
This product bundles pixman 0.32.8, which is available under an
"MIT" license. For details, see [project/lib/pixman/](project/lib).
diff --git a/project/lib/custom/openal/include/platforms/android/config_backends.h b/project/lib/custom/openal/include/platforms/android/config_backends.h
index 846380f595..e3de1614db 100644
--- a/project/lib/custom/openal/include/platforms/android/config_backends.h
+++ b/project/lib/custom/openal/include/platforms/android/config_backends.h
@@ -1,3 +1,13 @@
+#ifdef NATIVE_TOOLKIT_HAVE_SDL
+
+#define HAVE_OPENSL 0
+
+#else
+
+#define HAVE_OPENSL 1
+
+#endif
+
#define HAVE_ALSA 0
#define HAVE_OSS 0
@@ -22,6 +32,4 @@
#define HAVE_COREAUDIO 0
-#define HAVE_OPENSL 1
-
#define HAVE_OBOE 0
diff --git a/project/lib/custom/openal/include/platforms/apple/config_backends.h b/project/lib/custom/openal/include/platforms/apple/config_backends.h
index 0bb6c9b8e0..5a58db4e98 100644
--- a/project/lib/custom/openal/include/platforms/apple/config_backends.h
+++ b/project/lib/custom/openal/include/platforms/apple/config_backends.h
@@ -1,3 +1,13 @@
+#ifdef NATIVE_TOOLKIT_HAVE_SDL
+
+#define HAVE_COREAUDIO 0
+
+#else
+
+#define HAVE_COREAUDIO 1
+
+#endif
+
#define HAVE_ALSA 0
#define HAVE_OSS 0
@@ -20,8 +30,6 @@
#define HAVE_JACK 0
-#define HAVE_COREAUDIO 1
-
#define HAVE_OPENSL 0
#define HAVE_OBOE 0
diff --git a/project/lib/custom/openal/include/platforms/linux/config_backends.h b/project/lib/custom/openal/include/platforms/linux/config_backends.h
index c2a67ff433..8fde1bce3b 100644
--- a/project/lib/custom/openal/include/platforms/linux/config_backends.h
+++ b/project/lib/custom/openal/include/platforms/linux/config_backends.h
@@ -1,9 +1,23 @@
-#define HAVE_ALSA 1
+#ifdef NATIVE_TOOLKIT_HAVE_SDL
-#define HAVE_OSS 0
+#define HAVE_ALSA 0
+
+#define HAVE_PIPEWIRE 0
+
+#define HAVE_PULSEAUDIO 0
+
+#else
+
+#define HAVE_ALSA 1
#define HAVE_PIPEWIRE 1
+#define HAVE_PULSEAUDIO 1
+
+#endif
+
+#define HAVE_OSS 0
+
#define HAVE_SOLARIS 0
#define HAVE_SNDIO 0
@@ -16,8 +30,6 @@
#define HAVE_PORTAUDIO 0
-#define HAVE_PULSEAUDIO 1
-
#define HAVE_JACK 0
#define HAVE_COREAUDIO 0
diff --git a/project/lib/custom/openal/include/platforms/windows/config_backends.h b/project/lib/custom/openal/include/platforms/windows/config_backends.h
index 55bf169b75..39ce4b1bad 100644
--- a/project/lib/custom/openal/include/platforms/windows/config_backends.h
+++ b/project/lib/custom/openal/include/platforms/windows/config_backends.h
@@ -1,3 +1,17 @@
+#ifdef NATIVE_TOOLKIT_HAVE_SDL
+
+#define HAVE_WASAPI 0
+
+#define HAVE_DSOUND 0
+
+#else
+
+#define HAVE_WASAPI 1
+
+#define HAVE_DSOUND 1
+
+#endif
+
#define HAVE_ALSA 0
#define HAVE_OSS 0
@@ -8,10 +22,6 @@
#define HAVE_SNDIO 0
-#define HAVE_WASAPI 1
-
-#define HAVE_DSOUND 1
-
#define HAVE_WINMM 0
#define HAVE_PORTAUDIO 0
diff --git a/project/lib/custom/openal/include/version.h b/project/lib/custom/openal/include/version.h
index 46d0fe2c94..9eb13e4cab 100644
--- a/project/lib/custom/openal/include/version.h
+++ b/project/lib/custom/openal/include/version.h
@@ -6,4 +6,4 @@
#define ALSOFT_GIT_BRANCH "master"
/* Define the hash of the head commit */
-#define ALSOFT_GIT_COMMIT_HASH "1d52120"
+#define ALSOFT_GIT_COMMIT_HASH "0887e589"
diff --git a/project/lib/openal b/project/lib/openal
index e9c479eb41..0887e589fe 160000
--- a/project/lib/openal
+++ b/project/lib/openal
@@ -1 +1 @@
-Subproject commit e9c479eb4190101bc51179afae56fc6dd5d26066
+Subproject commit 0887e589fe2cc973fe0f5b9b61105711f2b35d79
diff --git a/project/lib/openal-files.xml b/project/lib/openal-files.xml
index c021774e52..cd7c0ce42e 100644
--- a/project/lib/openal-files.xml
+++ b/project/lib/openal-files.xml
@@ -131,13 +131,15 @@
+
+
+
-
-
@@ -201,6 +201,7 @@
+
diff --git a/src/lime/media/AudioManager.hx b/src/lime/media/AudioManager.hx
index c755401941..a8f1c04715 100644
--- a/src/lime/media/AudioManager.hx
+++ b/src/lime/media/AudioManager.hx
@@ -1,181 +1,617 @@
package lime.media;
-import lime.system.CFFIPointer;
import haxe.MainLoop;
-#if (windows || mac || linux || android || ios)
+import lime.app.Event;
+import lime.system.CFFIPointer;
+#if lime_openal
+import lime.media.openal.AL;
+import lime.media.openal.ALC;
+import lime.media.openal.ALContext;
+import lime.media.openal.ALDevice;
+#if lime_openalsoft
import haxe.io.Path;
import lime.system.System;
import sys.FileSystem;
import sys.io.File;
+import sys.thread.Mutex;
#end
-import haxe.Timer;
-import lime._internal.backend.native.NativeCFFI;
-import lime.media.openal.AL;
-import lime.media.openal.ALC;
-import lime.media.openal.ALContext;
-import lime.media.openal.ALDevice;
-import lime.app.Application;
-#if (js && html5)
-import js.Browser;
+#elseif lime_howlerjs
+import lime.media.howlerjs.Howler;
#end
#if !lime_debug
@:fileXml('tags="haxe,release"')
@:noDebug
#end
-@:access(lime._internal.backend.native.NativeCFFI)
@:access(lime.media.openal.ALDevice)
class AudioManager
{
+ /**
+ Should it automatically switch to the default playback device whenever it changes.
+
+ Only works on Native target.
+ **/
+ public static var automaticDefaultPlaybackDevice:Bool = true;
+
+ /**
+ The current used context to use for the audio manager.
+ **/
public static var context:AudioContext;
- public static function init(context:AudioContext = null)
+ /**
+ The gain (volume) of the audio manager. A value of `1.0` represents the default volume.
+ Property is in a linear scale.
+ **/
+ public static var gain(get, set):Float;
+
+ /**
+ Mutes the audio manager playback.
+ **/
+ public static var muted(get, set):Bool;
+
+ /**
+ Dispatched when the default for the playback device is changed.
+ 'Device Name' -> Void.
+
+ Only works on Native target.
+ **/
+ public static var onDefaultPlaybackDeviceChanged = new EventVoid>();
+
+ /**
+ Dispatched whenever a playback device is added.
+ 'Device Name' -> Void.
+
+ Only works on Native target.
+ **/
+ public static var onPlaybackDeviceAdded = new EventVoid>();
+
+ /**
+ Dispatched whenever a playback device is removed.
+ 'Device Name' -> Void.
+
+ Only works on Native target.
+ **/
+ public static var onPlaybackDeviceRemoved = new EventVoid>();
+
+ /**
+ Dispatched when the default for the capture device is changed.
+ 'Device Name' -> Void.
+
+ Only works on Native target.
+ **/
+ public static var onDefaultCaptureDeviceChanged = new EventVoid>();
+
+ /**
+ Dispatched whenever a capture device is added.
+ 'Device Name' -> Void.
+
+ Only works on Native target.
+ **/
+ public static var onCaptureDeviceAdded = new EventVoid>();
+
+ /**
+ Dispatched whenever a capture device is removed.
+ 'Device Name' -> Void.
+
+ Only works on Native target.
+ **/
+ public static var onCaptureDeviceRemoved = new EventVoid>();
+
+ @:noCompletion private static var __gain:Float = 1;
+ @:noCompletion private static var __muted:Bool = false;
+ #if lime_openal
+ #if lime_openalsoft
+ @:noCompletion private static var __pendingDeviceEventMutex:Mutex = new Mutex();
+ @:noCompletion private static var __pendingDeviceEventCheck:Bool;
+ @:noCompletion private static var __pendingPlaybackDevicesAddition:Array;
+ @:noCompletion private static var __pendingPlaybackDevicesRemoval:Array;
+ @:noCompletion private static var __pendingCaptureDevicesAddition:Array;
+ @:noCompletion private static var __pendingCaptureDevicesRemoval:Array;
+ @:noCompletion private static var __pendingDefaultPlaybackDevice:Bool;
+ @:noCompletion private static var __pendingDefaultCaptureDevice:Bool;
+ #end
+
+ @:noCompletion private static var __captureExtSupported:Bool;
+ @:noCompletion private static var __disconnectExtSupported:Bool;
+ @:noCompletion private static var __enumerateAllSupported:Bool;
+ @:noCompletion private static var __reopenDeviceSupported:Bool;
+ @:noCompletion private static var __systemEventsSupported:Bool;
+ #end
+
+ /**
+ Initializes an `AudioManager` to playback to and capture from audio devices.
+ Automatically dispatched when Application is constructed.
+
+ @param context Optional; An Audio Context to initalize the `AudioManager` with.
+ **/
+ public static function init(?context:AudioContext)
{
- if (AudioManager.context == null)
+ if (AudioManager.context != null) return;
+
+ if (context == null)
{
- if (context == null)
- {
- AudioManager.context = new AudioContext();
+ context = new AudioContext();
+ }
+
+ AudioManager.context = context;
+
+ #if lime_openal
+ if (context.type == OPENAL)
+ {
+ #if lime_openalsoft
+ __setupConfig();
+ #end
+
+ refresh();
+
+ #if lime_openalsoft
+ if (__reopenDeviceSupported) AL.disable(AL.STOP_SOURCES_ON_DISCONNECT_SOFT);
+ #if !mobile
+ if (__systemEventsSupported) {
+ ALC.eventControlSOFT([
+ ALC.EVENT_TYPE_DEFAULT_DEVICE_CHANGED_SOFT,
+ ALC.EVENT_TYPE_DEVICE_ADDED_SOFT,
+ ALC.EVENT_TYPE_DEVICE_REMOVED_SOFT],
+ true);
+ ALC.eventCallbackSOFT(__deviceEventCallback);
+ }
+ #end
+ #end
+ }
+ #end
+ }
+
+ /**
+ Gets the default capture audio device name from the host operating system.
+
+ Only works on Native target.
- context = AudioManager.context;
+ @return The default capture audio device name.
+ **/
+ public static function getCaptureDefaultDeviceName():String
+ {
+ #if (lime_openal && !lime_doc_gen)
+ if (context != null && context.type == OPENAL && __captureExtSupported)
+ {
+ return __formatDeviceName(ALC.getString(null, ALC.CAPTURE_DEFAULT_DEVICE_SPECIFIER));
+ }
+ #end
+ return '';
+ }
+
+ /**
+ Gets all of the available capture audio device names from the host operating system.
+ Note: "Default Device" is only exclusive in SDL3, this does not appear in every other OpenAL Soft backends.
+
+ Only works on Native target.
+
+ @return An array containing available capture audio device names.
+ **/
+ public static function getCaptureDeviceNames():Array
+ {
+ #if (lime_openal && !lime_doc_gen)
+ if (context == null || context.type != OPENAL || !__captureExtSupported) return [];
- #if !lime_doc_gen
- if (context.type == OPENAL)
+ final arr = ALC.getStringList(null, ALC.CAPTURE_DEVICE_SPECIFIER);
+ for (i in 0...arr.length) arr[i] = __formatDeviceName(arr[i]);
+
+ return arr;
+ #else
+ return [];
+ #end
+ }
+
+ /**
+ Gets the current used playback audio device name.
+
+ Only works on Native target.
+
+ @return Current playback audio device name.
+ **/
+ public static function getCurrentPlaybackDeviceName():String
+ {
+ #if (lime_openal && !lime_doc_gen)
+ if (context != null && context.type == OPENAL)
+ {
+ var currentContext = ALC.getCurrentContext();
+ if (currentContext != null)
+ {
+ var device = ALC.getContextsDevice(currentContext);
+ if (device != null)
{
- #if (windows || mac || linux || android || ios)
- setupConfig();
- #end
-
- var alc = context.openal;
- var device = alc.openDevice();
- if (device != null)
- {
- var ctx = alc.createContext(device);
- alc.makeContextCurrent(ctx);
- alc.processContext(ctx);
-
- #if (lime_openalsoft && !mobile)
- if (alc.isExtensionPresent('ALC_SOFT_system_events', device) && alc.isExtensionPresent('ALC_SOFT_reopen_device', device))
- {
- if (alc.isExtensionPresent('AL_SOFT_hold_on_disconnect'))
- alc.disable(AL.STOP_SOURCES_ON_DISCONNECT_SOFT);
-
- alc.eventControlSOFT([ALC.EVENT_TYPE_DEFAULT_DEVICE_CHANGED_SOFT, ALC.EVENT_TYPE_DEVICE_ADDED_SOFT, ALC.EVENT_TYPE_DEVICE_REMOVED_SOFT], true);
-
- alc.eventCallbackSOFT(deviceEventCallback);
- }
- #end
- }
+ if (__enumerateAllSupported) return __formatDeviceName(ALC.getString(device, ALC.ALL_DEVICES_SPECIFIER));
+ else return __formatDeviceName(ALC.getString(device, ALC.DEVICE_SPECIFIER));
}
- #end
}
+ }
+ #end
+ return '';
+ }
+
+ /**
+ Gets the default playback audio device name from the host operating system.
+
+ Only works on Native target.
+
+ @return The default playback audio device name.
+ **/
+ public static function getPlaybackDefaultDeviceName():String
+ {
+ #if (lime_openal && !lime_doc_gen)
+ if (context != null && context.type == OPENAL)
+ {
+ var deviceName:String;
+ if (__enumerateAllSupported) deviceName = __formatDeviceName(ALC.getString(null, ALC.DEFAULT_ALL_DEVICES_SPECIFIER));
+ else deviceName = __formatDeviceName(ALC.getString(null, ALC.DEFAULT_DEVICE_SPECIFIER));
+
+ if (deviceName == "Default Device") return getPlaybackDeviceNames()[0];
+ else return deviceName;
+ }
+ #end
+ return '';
+ }
+
+ /**
+ Gets all of the available playback audio device names from the host operating system.
- AudioManager.context = context;
+ Only works on Native target.
+
+ @return An array containing available playback audio device names.
+ **/
+ public static function getPlaybackDeviceNames():Array
+ {
+ #if (lime_openal && !lime_doc_gen)
+ if (context == null || context.type != OPENAL) return [];
+ else if (!__enumerateAllSupported) return [__formatDeviceName(ALC.getString(null, ALC.DEVICE_SPECIFIER))];
+
+ final arr = ALC.getStringList(null, ALC.ALL_DEVICES_SPECIFIER);
+ for (i in 0...arr.length) arr[i] = __formatDeviceName(arr[i]);
+
+ // SDL3 Backend Exclusive, apparently not a bug but it acts as a virtual device to automatically
+ // switch to a default device without having to code it on your own, except that it's
+ // been already coded so this isn't needed anymore.
+ arr.remove("Default Device");
+
+ return arr;
+ #else
+ return [];
+ #end
+ }
+
+ /**
+ Refresh the context with optionally to different device.
+
+ Only works on Native target.
+
+ @param deviceName Optional; The device name to use to for playbacking the audios.
+ **/
+ public static function refresh(?deviceName:String):Bool
+ {
+ #if (lime_openal && !lime_doc_gen)
+ if (context == null || context.type != OPENAL) return false;
+
+ if (deviceName == null) deviceName = getPlaybackDefaultDeviceName();
+
+ var currentContext = ALC.getCurrentContext();
+ var device = currentContext != null ? ALC.getContextsDevice(currentContext) : null;
+
+ #if (lime_openalsoft && !mobile)
+ if (device != null && __reopenDeviceSupported && ALC.reopenDeviceSOFT(device, deviceName, null))
+ {
+ __refresh();
+ return true;
}
+ #end
+
+ if (currentContext != null)
+ {
+ ALC.destroyContext(currentContext);
+ currentContext = null;
+ }
+
+ if (device != null)
+ {
+ ALC.closeDevice(device);
+ device = null;
+ }
+
+ if ((device = ALC.openDevice()) == null || (currentContext = ALC.createContext(device)) == null
+ || !ALC.makeContextCurrent(currentContext))
+ {
+ return false;
+ }
+
+ ALC.processContext(currentContext);
+ __refresh();
+ return true;
+ #else
+ return false;
+ #end
}
+ /**
+ Resumes the current `AudioManager` context.
+ **/
public static function resume():Void
{
- #if !lime_doc_gen
+ #if lime_openal
if (context != null && context.type == OPENAL)
{
- var alc = context.openal;
- var currentContext = alc.getCurrentContext();
-
+ var currentContext = ALC.getCurrentContext();
if (currentContext != null)
{
- var device = alc.getContextsDevice(currentContext);
- alc.resumeDevice(device);
- alc.processContext(currentContext);
+ var device = ALC.getContextsDevice(currentContext);
+ if (device != null) ALC.resumeDevice(device);
+
+ ALC.processContext(currentContext);
}
}
+ #elseif (js && html5)
+ #if lime_howlerjs
+ if (untyped Howler.ctx)
+ {
+ Howler.ctx.resume();
+ }
+ #end
+ if (context != null && context.type == WEB)
+ {
+ context.web.resume();
+ }
#end
}
+ /**
+ Shutdowns the current `AudioManager` context.
+ **/
public static function shutdown():Void
{
- #if !lime_doc_gen
+ #if lime_openal
if (context != null && context.type == OPENAL)
{
- var alc = context.openal;
- var currentContext = alc.getCurrentContext();
- var device = alc.getContextsDevice(currentContext);
-
+ var currentContext = ALC.getCurrentContext();
if (currentContext != null)
{
- alc.makeContextCurrent(null);
- alc.destroyContext(currentContext);
+ ALC.makeContextCurrent(null);
+ ALC.destroyContext(currentContext);
- if (device != null)
- {
- alc.closeDevice(device);
- }
+ var device = ALC.getContextsDevice(currentContext);
+ if (device != null) ALC.closeDevice(device);
}
}
+ #elseif (js && html5)
+ #if lime_howlerjs
+ if (untyped Howler.ctx)
+ {
+ Howler.ctx.unload();
+ }
+ #end
+ if (context != null && context.type == WEB)
+ {
+ context.web.close();
+ }
#end
context = null;
}
+ /**
+ Pauses the current `AudioManager` context.
+ **/
public static function suspend():Void
{
- #if !lime_doc_gen
+ #if lime_openal
if (context != null && context.type == OPENAL)
{
- var alc = context.openal;
- var currentContext = alc.getCurrentContext();
- var device = alc.getContextsDevice(currentContext);
-
+ var currentContext = ALC.getCurrentContext();
if (currentContext != null)
{
- alc.suspendContext(currentContext);
+ ALC.suspendContext(currentContext);
- if (device != null)
- {
- alc.pauseDevice(device);
- }
+ var device = ALC.getContextsDevice(currentContext);
+ if (device != null) ALC.pauseDevice(device);
}
}
+ #elseif (js && html5)
+ #if lime_howlerjs
+ if (untyped Howler.ctx)
+ {
+ Howler.ctx.suspend();
+ }
#end
+ if (context != null && context.type == WEB)
+ {
+ context.web.suspend();
+ }
+ #end
+ }
+
+ @:noCompletion private static inline function get_muted():Bool
+ {
+ return __muted;
+ }
+
+ @:noCompletion private static inline function set_muted(value:Bool):Bool
+ {
+ __muted = value;
+ if (context == null) return __muted;
+
+ #if !lime_doc_gen
+ #if lime_openal
+ if (context.type == OPENAL) AL.listenerf(AL.GAIN, value ? 0 : __gain);
+ #elseif (js && html5 && lime_howlerjs)
+ Howler.mute(value);
+ #end
+ #end
+ return value;
+ }
+
+ @:noCompletion private static inline function get_gain():Float
+ {
+ return __gain;
+ }
+
+ @:noCompletion private static inline function set_gain(value:Float):Float
+ {
+ __gain = value;
+ if (context == null) return __gain;
+
+ #if !lime_doc_gen
+ #if lime_openal
+ if (context.type == OPENAL) AL.listenerf(AL.GAIN, __muted ? 0 : value);
+ #elseif (js && html5 && lime_howlerjs)
+ Howler.volume(value);
+ #end
+ #end
+ return value;
+ }
+
+ #if (lime_openal && !lime_doc_gen)
+ @:noCompletion private static function __refresh():Void
+ {
+ var currentContext = ALC.getCurrentContext();
+ if (currentContext == null) return;
+
+ var device = ALC.getContextsDevice(currentContext);
+ if (device == null) return;
+
+ __captureExtSupported = ALC.isExtensionPresent(null, 'ALC_EXT_CAPTURE');
+ __disconnectExtSupported = ALC.isExtensionPresent(null, 'ALC_EXT_disconnect');
+ __enumerateAllSupported = ALC.isExtensionPresent(null, 'ALC_ENUMERATE_ALL_EXT');
+ __reopenDeviceSupported = ALC.isExtensionPresent(null, 'ALC_SOFT_reopen_device');
+ __systemEventsSupported = ALC.isExtensionPresent(null, 'ALC_SOFT_system_events');
+
+ gain = __gain;
+ AL.distanceModel(AL.NONE);
+ }
+
+ @:noCompletion private static function __formatDeviceName(deviceName:String)
+ {
+ #if lime_openalsoft
+ if (StringTools.startsWith(deviceName, 'OpenAL Soft on ')) return deviceName.substr(15);
+ #elseif lime_openal
+ if (StringTools.startsWith(deviceName, 'OpenAL on ')) return deviceName.substr(10);
+ #end
+ else if (StringTools.startsWith(deviceName, 'Generic Software on ')) return deviceName.substr(20);
+ else return deviceName;
}
#if lime_openalsoft
@:noCompletion
- private static function deviceEventCallback(eventType:Int, deviceType:Int, handle:CFFIPointer, message:#if hl hl.Bytes #else String #end):Void
+ private static function __deviceEventRun():Void
{
- #if !lime_doc_gen
- if (eventType == ALC.EVENT_TYPE_DEFAULT_DEVICE_CHANGED_SOFT && deviceType == ALC.PLAYBACK_DEVICE_SOFT)
+ __pendingDeviceEventMutex.acquire();
+
+ if (__pendingDefaultPlaybackDevice)
{
- var device = new ALDevice(handle);
+ __pendingDefaultPlaybackDevice = false;
+ if (automaticDefaultPlaybackDevice) refresh();
+ onDefaultPlaybackDeviceChanged.dispatch(getPlaybackDefaultDeviceName());
+ }
- MainLoop.runInMainThread(function():Void
- {
- var alc = context.openal;
+ if (__pendingDefaultCaptureDevice)
+ {
+ __pendingDefaultCaptureDevice = false;
+ onDefaultCaptureDeviceChanged.dispatch(getCaptureDefaultDeviceName());
+ }
- if (device == null)
- {
- var currentContext = alc.getCurrentContext();
+ if (__pendingPlaybackDevicesAddition != null)
+ {
+ for (deviceName in __pendingPlaybackDevicesAddition) onPlaybackDeviceAdded.dispatch(deviceName);
+ __pendingPlaybackDevicesAddition = null;
+ }
- var device = alc.getContextsDevice(currentContext);
+ if (__pendingPlaybackDevicesRemoval != null)
+ {
+ for (deviceName in __pendingPlaybackDevicesRemoval) onPlaybackDeviceRemoved.dispatch(deviceName);
+ __pendingPlaybackDevicesRemoval = null;
+ }
- if (device != null)
- alc.reopenDeviceSOFT(device, null, null);
- }
- else
- {
- alc.reopenDeviceSOFT(device, null, null);
- }
+ if (__pendingCaptureDevicesAddition != null)
+ {
+ for (deviceName in __pendingCaptureDevicesAddition) onCaptureDeviceAdded.dispatch(deviceName);
+ __pendingCaptureDevicesAddition = null;
+ }
- });
+ if (__pendingCaptureDevicesRemoval != null)
+ {
+ for (deviceName in __pendingCaptureDevicesRemoval) onCaptureDeviceRemoved.dispatch(deviceName);
+ __pendingCaptureDevicesRemoval = null;
}
- #end
+
+ __pendingDeviceEventCheck = false;
+ __pendingDeviceEventMutex.release();
}
- #end
@:noCompletion
- private static function setupConfig():Void
+ private static function __deviceEventCallback(eventType:Int, deviceType:Int, handle:CFFIPointer,
+ #if hl _message:hl.Bytes #else message:String #end)
+ {
+ #if hl var message:String = CFFI.stringValue(_message); #end
+ var device:ALDevice = handle != null ? new ALDevice(handle) : null;
+ var deviceName = __getDeviceNameFromMessage(message);
+
+ var currentContext = ALC.getCurrentContext();
+ var currentDevice = currentContext != null ? ALC.getContextsDevice(currentContext) : null;
+
+ __pendingDeviceEventMutex.acquire();
+
+ if (deviceType == ALC.PLAYBACK_DEVICE_SOFT)
+ {
+ switch (eventType)
+ {
+ case ALC.EVENT_TYPE_DEFAULT_DEVICE_CHANGED_SOFT:
+ __pendingDefaultPlaybackDevice = true;
+ case ALC.EVENT_TYPE_DEVICE_ADDED_SOFT:
+ var formattedDeviceName = __formatDeviceName(deviceName);
+ if (__pendingPlaybackDevicesRemoval != null) __pendingPlaybackDevicesRemoval.remove(formattedDeviceName);
+ if (__pendingPlaybackDevicesAddition == null) __pendingPlaybackDevicesAddition = [];
+ __pendingPlaybackDevicesAddition.push(formattedDeviceName);
+ case ALC.EVENT_TYPE_DEVICE_REMOVED_SOFT:
+ var formattedDeviceName = __formatDeviceName(deviceName);
+ if (__pendingPlaybackDevicesAddition != null) __pendingPlaybackDevicesAddition.remove(formattedDeviceName);
+ if (__pendingPlaybackDevicesRemoval == null) __pendingPlaybackDevicesRemoval = [];
+ __pendingPlaybackDevicesRemoval.push(formattedDeviceName);
+ }
+ }
+ else if (deviceType == ALC.CAPTURE_DEVICE_SOFT)
+ {
+ switch (eventType)
+ {
+ case ALC.EVENT_TYPE_DEFAULT_DEVICE_CHANGED_SOFT:
+ __pendingDefaultCaptureDevice = true;
+ case ALC.EVENT_TYPE_DEVICE_ADDED_SOFT:
+ var formattedDeviceName = __formatDeviceName(deviceName);
+ if (__pendingCaptureDevicesRemoval != null) __pendingCaptureDevicesRemoval.remove(formattedDeviceName);
+ if (__pendingCaptureDevicesAddition == null) __pendingCaptureDevicesAddition = [];
+ __pendingCaptureDevicesAddition.push(formattedDeviceName);
+ case ALC.EVENT_TYPE_DEVICE_REMOVED_SOFT:
+ var formattedDeviceName = __formatDeviceName(deviceName);
+ if (__pendingCaptureDevicesAddition != null) __pendingCaptureDevicesAddition.remove(formattedDeviceName);
+ if (__pendingCaptureDevicesRemoval == null) __pendingCaptureDevicesRemoval = [];
+ __pendingCaptureDevicesRemoval.push(formattedDeviceName);
+ }
+ }
+
+ if (!__pendingDeviceEventCheck)
+ {
+ __pendingDeviceEventCheck = true;
+ MainLoop.runInMainThread(__deviceEventRun);
+ }
+
+ __pendingDeviceEventMutex.release();
+ }
+
+ @:noCompletion
+ private static function __getDeviceNameFromMessage(message:String):Null
+ {
+ if (StringTools.startsWith(message, 'Device removed: ')) return message.substr(16);
+ else if (StringTools.startsWith(message, 'Device added: ')) return message.substr(14);
+ else return null;
+ }
+
+ @:noCompletion
+ private static function __setupConfig():Void
{
- #if (lime_openal && (windows || mac || linux || android || ios))
final alConfig:Array = [];
alConfig.push('[general]');
@@ -209,6 +645,7 @@ class AudioManager
Sys.putEnv('ALSOFT_CONF', path);
}
catch (e:Dynamic) {}
- #end
}
+ #end
+ #end
}
diff --git a/src/lime/media/WebAudioContext.hx b/src/lime/media/WebAudioContext.hx
index 89dac24a39..d0215203fa 100644
--- a/src/lime/media/WebAudioContext.hx
+++ b/src/lime/media/WebAudioContext.hx
@@ -20,6 +20,16 @@ class WebAudioContext
}
#end
+ public function suspend():Dynamic /*Promise*/
+ {
+ return null;
+ }
+
+ public function close():Dynamic /*Promise*/
+ {
+ return null;
+ }
+
public function createAnalyser():Dynamic /*AnalyserNode*/
{
return null;