diff --git a/project/src/media/openal/OpenALBindings.cpp b/project/src/media/openal/OpenALBindings.cpp index b978911df3..d46514d351 100644 --- a/project/src/media/openal/OpenALBindings.cpp +++ b/project/src/media/openal/OpenALBindings.cpp @@ -3425,6 +3425,68 @@ namespace lime { } + value lime_alc_get_string_list (value device, int param) { + + ALCdevice* alcDevice = (ALCdevice*)val_data (device); + const char* values = alcGetString (alcDevice, param); + + if (!values) { + return alloc_array (0); + } + + int count = 0; + const char* ptr = values; + while (*ptr) { + count++; + ptr += strlen (ptr) + 1; + } + + value result = alloc_array (count); + ptr = values; + count = 0; + while (*ptr) { + val_array_set_i (result, count, alloc_string (ptr)); + count++; + ptr += strlen (ptr) + 1; + } + + return result; + + } + + + HL_PRIM varray* HL_NAME(hl_alc_get_string_list) (HL_CFFIPointer* device, int param) { + + ALCdevice* alcDevice = device ? (ALCdevice*)device->ptr : 0; + const char* values = alcGetString (alcDevice, param); + + if (!values) { + return hl_alloc_array (&hlt_bytes, 0); + } + + int count = 0; + const char* ptr = values; + while (*ptr) { + count++; + ptr += strlen (ptr) + 1; + } + + varray* result = hl_alloc_array(&hlt_bytes, count); + ptr = values; + count = 0; + while (*ptr) { + char* _result = (char*)malloc (strlen (ptr) + 1); + strcpy (_result, ptr); + hl_aptr (result, vbyte*)[count] = (vbyte*)_result; + count++; + ptr += strlen (ptr) + 1; + } + + return result; + + } + + bool lime_alc_make_context_current (value context) { ALCcontext* alcContext = (ALCcontext*)val_data (context); @@ -3584,7 +3646,7 @@ namespace lime { al_gc_mutex.Lock (); - alSoftEventCallback->Call (alloc_int((int)eventType), alloc_int((int)deviceType), CFFIPointer (device), message ? alloc_string(message) : alloc_null()); + alSoftEventCallback->Call (alloc_int((int)eventType), alloc_int((int)deviceType), (value)CFFIPointer (device), message ? alloc_string(message) : alloc_null()); al_gc_mutex.Unlock (); @@ -3827,6 +3889,7 @@ namespace lime { DEFINE_PRIME1 (lime_alc_get_error); DEFINE_PRIME3 (lime_alc_get_integerv); DEFINE_PRIME2 (lime_alc_get_string); + DEFINE_PRIME2 (lime_alc_get_string_list); DEFINE_PRIME1 (lime_alc_make_context_current); DEFINE_PRIME1 (lime_alc_open_device); DEFINE_PRIME1v (lime_alc_pause_device); @@ -3954,6 +4017,7 @@ namespace lime { DEFINE_HL_PRIM (_I32, hl_alc_get_error, _TCFFIPOINTER); DEFINE_HL_PRIM (_ARR, hl_alc_get_integerv, _TCFFIPOINTER _I32 _I32); DEFINE_HL_PRIM (_BYTES, hl_alc_get_string, _TCFFIPOINTER _I32); + DEFINE_HL_PRIM (_ARR, hl_alc_get_string_list, _TCFFIPOINTER _I32); DEFINE_HL_PRIM (_BOOL, hl_alc_make_context_current, _TCFFIPOINTER); DEFINE_HL_PRIM (_TCFFIPOINTER, hl_alc_open_device, _STRING); DEFINE_HL_PRIM (_VOID, hl_alc_pause_device, _TCFFIPOINTER); diff --git a/src/lime/_internal/backend/native/NativeCFFI.hx b/src/lime/_internal/backend/native/NativeCFFI.hx index 22968a536e..6258aac56f 100644 --- a/src/lime/_internal/backend/native/NativeCFFI.hx +++ b/src/lime/_internal/backend/native/NativeCFFI.hx @@ -1553,6 +1553,12 @@ class NativeCFFI @:cffi private static function lime_al_delete_sources(n:Int, sources:Dynamic):Void; + @:cffi private static function lime_al_delete_effect(buffer:CFFIPointer):Void; + + @:cffi private static function lime_al_delete_filter(buffer:CFFIPointer):Void; + + @:cffi private static function lime_al_delete_auxiliary_effect_slot(slot:CFFIPointer):Void; + @:cffi private static function lime_al_disable(capability:Int):Void; @:cffi private static function lime_al_distance_model(distanceModel:Int):Void; @@ -1703,6 +1709,8 @@ class NativeCFFI @:cffi private static function lime_alc_get_string(device:CFFIPointer, param:Int):Dynamic; + @:cffi private static function lime_alc_get_string_list(device:CFFIPointer, param:Int):Dynamic; + @:cffi private static function lime_alc_make_context_current(context:CFFIPointer):Bool; @:cffi private static function lime_alc_open_device(devicename:String):CFFIPointer; @@ -1779,6 +1787,10 @@ class NativeCFFI private static var lime_al_delete_source = new cpp.Callablecpp.Void>(cpp.Prime._loadPrime("lime", "lime_al_delete_source", "ov", false)); private static var lime_al_delete_sources = new cpp.Callablecpp.Object->cpp.Void>(cpp.Prime._loadPrime("lime", "lime_al_delete_sources", "iov", false)); + private static var lime_al_delete_effect = new cpp.Callablecpp.Void>(cpp.Prime._loadPrime("lime", "lime_al_delete_effect", "ov", false)); + private static var lime_al_delete_filter = new cpp.Callablecpp.Void>(cpp.Prime._loadPrime("lime", "lime_al_delete_filter", "ov", false)); + private static var lime_al_delete_auxiliary_effect_slot = new cpp.Callablecpp.Void>(cpp.Prime._loadPrime("lime", + "lime_al_delete_auxiliary_effect_slot", "ov", false)); private static var lime_al_disable = new cpp.Callablecpp.Void>(cpp.Prime._loadPrime("lime", "lime_al_disable", "iv", false)); private static var lime_al_distance_model = new cpp.Callablecpp.Void>(cpp.Prime._loadPrime("lime", "lime_al_distance_model", "iv", false)); private static var lime_al_doppler_factor = new cpp.Callablecpp.Void>(cpp.Prime._loadPrime("lime", "lime_al_doppler_factor", "fv", false)); @@ -1881,6 +1893,7 @@ class NativeCFFI private static var lime_alc_get_integerv = new cpp.CallableInt->Int->cpp.Object>(cpp.Prime._loadPrime("lime", "lime_alc_get_integerv", "oiio", false)); private static var lime_alc_get_string = new cpp.CallableInt->cpp.Object>(cpp.Prime._loadPrime("lime", "lime_alc_get_string", "oio", false)); + private static var lime_alc_get_string_list = new cpp.CallableInt->cpp.Object>(cpp.Prime._loadPrime("lime", "lime_alc_get_string_list", "oio", false)); private static var lime_alc_make_context_current = new cpp.CallableBool>(cpp.Prime._loadPrime("lime", "lime_alc_make_context_current", "ob", false)); private static var lime_alc_open_device = new cpp.Callablecpp.Object>(cpp.Prime._loadPrime("lime", "lime_alc_open_device", "so", false)); @@ -1936,6 +1949,9 @@ class NativeCFFI private static var lime_al_delete_buffers = CFFI.load("lime", "lime_al_delete_buffers", 2); private static var lime_al_delete_source = CFFI.load("lime", "lime_al_delete_source", 1); private static var lime_al_delete_sources = CFFI.load("lime", "lime_al_delete_sources", 2); + private static var lime_al_delete_effect = CFFI.load("lime", "lime_al_delete_effect", 1); + private static var lime_al_delete_filter = CFFI.load("lime", "lime_al_delete_filter", 1); + private static var lime_al_delete_auxiliary_effect_slot = CFFI.load("lime", "lime_al_delete_auxiliary_effect_slot", 1); private static var lime_al_disable = CFFI.load("lime", "lime_al_disable", 1); private static var lime_al_distance_model = CFFI.load("lime", "lime_al_distance_model", 1); private static var lime_al_doppler_factor = CFFI.load("lime", "lime_al_doppler_factor", 1); @@ -2011,6 +2027,7 @@ class NativeCFFI private static var lime_alc_get_error = CFFI.load("lime", "lime_alc_get_error", 1); private static var lime_alc_get_integerv = CFFI.load("lime", "lime_alc_get_integerv", 3); private static var lime_alc_get_string = CFFI.load("lime", "lime_alc_get_string", 2); + private static var lime_alc_get_string_list = CFFI.load("lime", "lime_alc_get_string_list", 2); private static var lime_alc_make_context_current = CFFI.load("lime", "lime_alc_make_context_current", 1); private static var lime_alc_open_device = CFFI.load("lime", "lime_alc_open_device", 1); private static var lime_alc_pause_device = CFFI.load("lime", "lime_alc_pause_device", 1); @@ -2068,6 +2085,12 @@ class NativeCFFI @:hlNative("lime", "hl_al_delete_sources") private static function lime_al_delete_sources(n:Int, sources:hl.NativeArray):Void {} + @:hlNative("lime", "lime_al_delete_effect") private static function lime_al_delete_effect(buffer:CFFIPointer):Void {} + + @:hlNative("lime", "lime_al_delete_filter") private static function lime_al_delete_filter(buffer:CFFIPointer):Void {} + + @:hlNative("lime", "lime_al_delete_auxiliary_effect_slot") private static function lime_al_delete_auxiliary_effect_slot(slot:CFFIPointer):Void {} + @:hlNative("lime", "hl_al_disable") private static function lime_al_disable(capability:Int):Void {} @:hlNative("lime", "hl_al_distance_model") private static function lime_al_distance_model(distanceModel:Int):Void {} @@ -2363,6 +2386,11 @@ class NativeCFFI return null; } + @:hlNative("lime", "hl_alc_get_string_list") private static function lime_alc_get_string_list(device:CFFIPointer, param:Int):hl.NativeArray + { + return null; + } + @:hlNative("lime", "hl_alc_make_context_current") private static function lime_alc_make_context_current(context:ALContext):Bool { return false; diff --git a/src/lime/media/AudioManager.hx b/src/lime/media/AudioManager.hx index 5faf7b33b9..3910162ff6 100644 --- a/src/lime/media/AudioManager.hx +++ b/src/lime/media/AudioManager.hx @@ -1,22 +1,23 @@ package lime.media; -import lime.system.CFFIPointer; import haxe.MainLoop; -#if (windows || mac || linux || android || ios) +import haxe.Timer; +import lime.system.CFFIPointer; +import lime.app.Application; +import lime.app.Event; +#if lime_openal +#if sys import haxe.io.Path; import lime.system.System; import sys.FileSystem; import sys.io.File; #end -import haxe.Timer; +import sys.thread.Deque; 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; #end #if !lime_debug @@ -27,179 +28,302 @@ import js.Browser; @:access(lime.media.openal.ALDevice) class AudioManager { + /** + The current used context to use for the audio manager. + **/ public static var context:AudioContext; + /** + Dispatched when the default for the playback device is changed. + 'Device Name' -> Void. + **/ + public static var onDefaultPlaybackDeviceChanged = new EventVoid>(); + + /** + Dispatched whenever a playback device is added. + 'Device Name' -> Void. + **/ + public static var onPlaybackDeviceAdded = new EventVoid>(); + + /** + Dispatched whenever a playback device is removed. + 'Device Name' -> Void. + **/ + public static var onPlaybackDeviceRemoved = new EventVoid>(); + + /** + Dispatched when the default for the capture device is changed. + 'Device Name' -> Void. + **/ + public static var onDefaultCaptureDeviceChanged = new EventVoid>(); + + /** + Dispatched whenever a capture device is added. + 'Device Name' -> Void. + **/ + public static var onCaptureDeviceAdded = new EventVoid>(); + + /** + Dispatched whenever a capture device is removed. + 'Device Name' -> Void. + **/ + public static var onCaptureDeviceRemoved = new EventVoid>(); + + /** + Should it automatically switch to the default playback device whenever it changes. + **/ + public static var automaticDefaultPlaybackDevice:Bool = true; + + @:noCompletion private static var __updateTimer:Timer; + #if lime_openal + @:noCompletion private static var __captureExtSupported:Bool; + @:noCompletion private static var __disconnectExtSupported:Bool; + @:noCompletion private static var __reopenDeviceSupported:Bool; + @:noCompletion private static var __systemEventsSupported:Bool; + @:noCompletion private static var __enumerateAllSupported:Bool; + + @:noCompletion private static var __latencyExtensionSupported:Bool; + @:noCompletion private static var __loopPointsSupported:Bool; + @:noCompletion private static var __moreFormatsSupported:Bool; + @:noCompletion private static var __spatializeSupported:Bool; + @:noCompletion private static var __stereoAnglesSupported:Bool; + + @:noCompletion private static var __alRequestEvents:Deque = new Deque(); + #end + public static function init(context:AudioContext = null) { - if (AudioManager.context == null) + #if !lime_doc_gen + if (AudioManager.context != null) return; + + if (context == null) { - if (context == null) - { - AudioManager.context = new AudioContext(); + AudioManager.context = new AudioContext(); + context = AudioManager.context; - context = AudioManager.context; + #if lime_openal + if (context.type == OPENAL) + { + __setupConfig(); + refresh(); + + AL.distanceModel(AL.NONE); + if (__reopenDeviceSupported) AL.disable(AL.STOP_SOURCES_ON_DISCONNECT_SOFT); + 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(__alDeviceEventCallback); + } + } + #end + } - #if !lime_doc_gen - if (context.type == OPENAL) - { - #if (windows || mac || linux || android || ios) - setupConfig(); - #end + if (__updateTimer == null) + { + __updateTimer = new Timer(100); + __updateTimer.run = __update; + } - var alc = context.openal; - var device = alc.openDevice(); - var ctx = alc.createContext(device); + gain = 1; + #end + } - alc.makeContextCurrent(ctx); - alc.processContext(ctx); + public static function refresh(?deviceName:String):Bool + { + #if (lime_openal && !lime_doc_gen) + if (context == null || context.type != OPENAL) return false; - #if !(neko || mobile) - if (alc.isExtensionPresent('ALC_SOFT_system_events', device) && alc.isExtensionPresent('ALC_SOFT_reopen_device', device)) - { - alc.disable(AL.STOP_SOURCES_ON_DISCONNECT_SOFT); + var currentContext = ALC.getCurrentContext(); + var device = currentContext != null ? ALC.getContextsDevice(currentContext) : null; - alc.eventControlSOFT([ALC.EVENT_TYPE_DEFAULT_DEVICE_CHANGED_SOFT, ALC.EVENT_TYPE_DEVICE_ADDED_SOFT, ALC.EVENT_TYPE_DEVICE_REMOVED_SOFT], true); + if (device != null && __reopenDeviceSupported && ALC.reopenDeviceSOFT(device, deviceName, null)) + { + __refresh(); + return true; + } - alc.eventCallbackSOFT(deviceEventCallback); - } - #end - } - #end - } + if (currentContext != null) + { + ALC.destroyContext(currentContext); + currentContext = null; + } - AudioManager.context = context; + if (device != null) + { + ALC.closeDevice(device); + device = null; + } - #if (lime_cffi && !macro && lime_openal && (ios || tvos || mac)) - var timer = new Timer(100); - timer.run = function() - { - NativeCFFI.lime_al_cleanup(); - }; - #end + 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 } - public static function resume():Void + public static function getCurrentPlaybackDeviceName():String { - #if !lime_doc_gen + #if (lime_openal && !lime_doc_gen) 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) + { + if (__enumerateAllSupported) return ALC.getString(device, ALC.ALL_DEVICES_SPECIFIER); + else return ALC.getString(device, ALC.DEVICE_SPECIFIER); + } } } #end + return ''; } - public static function shutdown():Void + public static function getPlaybackDefaultDeviceName():String { - #if !lime_doc_gen + #if (lime_openal && !lime_doc_gen) if (context != null && context.type == OPENAL) { - var alc = context.openal; - var currentContext = alc.getCurrentContext(); - var device = alc.getContextsDevice(currentContext); + if (__enumerateAllSupported) return __formatDeviceName(ALC.getString(null, ALC.DEFAULT_ALL_DEVICES_SPECIFIER)); + else return __formatDeviceName(ALC.getString(null, ALC.DEFAULT_DEVICE_SPECIFIER)); + } + #end + return ''; + } - if (currentContext != null) - { - alc.makeContextCurrent(null); - alc.destroyContext(currentContext); + public static function getPlaybackDeviceNames():Array + { + #if (lime_openal && !lime_doc_gen) + if (context == null || context.type != OPENAL) return []; + else if (!__enumerateAllSupported) return [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]); + return arr; + #else + return []; + #end + } - if (device != null) - { - alc.closeDevice(device); - } - } + 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 ''; + } - context = null; + public static function getCaptureDeviceNames():Array + { + #if (lime_openal && !lime_doc_gen) + if (context == null || context.type != OPENAL || !__captureExtSupported) return []; + + 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 } - public static function suspend():Void + public static function resume():Void { - #if !lime_doc_gen - if (context != null && context.type == OPENAL) - { - var alc = context.openal; - var currentContext = alc.getCurrentContext(); - var device = alc.getContextsDevice(currentContext); + #if (lime_openal && !lime_doc_gen) + if (context == null || context.type != OPENAL) return; - if (currentContext != null) - { - alc.suspendContext(currentContext); + var currentContext = ALC.getCurrentContext(); + if (currentContext == null) return; - if (device != null) - { - alc.pauseDevice(device); - } - } - } + var device = ALC.getContextsDevice(currentContext); + if (device != null) ALC.resumeDevice(device); + + ALC.processContext(currentContext); #end } - @:noCompletion - #if hl - private static function deviceEventCallback(eventType:Int, deviceType:Int, handle:CFFIPointer, message:hl.Bytes):Void - #else - private static function deviceEventCallback(eventType:Int, deviceType:Int, handle:CFFIPointer, message:String):Void - #end + public static function shutdown():Void { - #if !lime_doc_gen - if (eventType == ALC.EVENT_TYPE_DEFAULT_DEVICE_CHANGED_SOFT && deviceType == ALC.PLAYBACK_DEVICE_SOFT) - { - var device = new ALDevice(handle); + #if (lime_openal && !lime_doc_gen) + if (context == null || context.type != OPENAL) return; - MainLoop.runInMainThread(function():Void - { - var alc = context.openal; + var currentContext = ALC.getCurrentContext(); + if (currentContext == null) return; - if (device == null) - { - var currentContext = alc.getCurrentContext(); + ALC.makeContextCurrent(null); + ALC.destroyContext(currentContext); - var device = alc.getContextsDevice(currentContext); + var device = ALC.getContextsDevice(currentContext); + if (device != null) ALC.closeDevice(device); + #end - if (device != null) - alc.reopenDeviceSOFT(device, null, null); - } - else - { - alc.reopenDeviceSOFT(device, null, null); - } + context = null; + } + + public static function suspend():Void + { + #if (lime_openal && !lime_doc_gen) + if (context == null || context.type != OPENAL) return; + + var currentContext = ALC.getCurrentContext(); + if (currentContext == null) return; + + ALC.suspendContext(currentContext); + + var device = ALC.getContextsDevice(currentContext); + if (device != null) ALC.pauseDevice(device); + #end + } + + @:noCompletion private static function __update():Void + { + #if (lime_openal && !lime_doc_gen) + NativeCFFI.lime_al_cleanup(); - }); + if (__systemEventsSupported) { + var request; + while ((request = __alRequestEvents.pop(false)) != null) + __deviceEventCallback(request.eventType, request.deviceType, request.device, request.deviceName, request.message); } #end } - @:noCompletion - private static function setupConfig():Void + + #if (lime_openal && !lime_doc_gen) + @:noCompletion private static function __setupConfig():Void { - #if (lime_openal && (windows || mac || linux || android || ios)) + #if sys final alConfig:Array = []; - alConfig.push('[general]'); - alConfig.push('channels=stereo'); + alConfig.push('[General]'); alConfig.push('sample-type=float32'); - alConfig.push('stereo-mode=speakers'); - alConfig.push('stereo-encoding=panpot'); + alConfig.push('channels=stereo'); alConfig.push('hrtf=false'); alConfig.push('cf_level=0'); - alConfig.push('resampler=fast_bsinc24'); - alConfig.push('front-stablizer=false'); alConfig.push('output-limiter=false'); + alConfig.push('front-stablizer=false'); alConfig.push('volume-adjust=0'); alConfig.push('period_size=441'); + alConfig.push('sources=512'); + alConfig.push('sends=64'); + alConfig.push('dither=false'); alConfig.push('[decoder]'); - alConfig.push('hq-mode=false'); + alConfig.push('hq-mode=true'); alConfig.push('distance-comp=false'); alConfig.push('nfc=false'); @@ -211,11 +335,105 @@ class AudioManager if (!FileSystem.exists(directory)) FileSystem.createDirectory(directory); - if (!FileSystem.exists(path)) File.saveContent(path, content); + var output = File.write(path, false); + output.writeString(content); + output.close(); Sys.putEnv('ALSOFT_CONF', path); } catch (e:Dynamic) {} #end } + + // device is null... and its actually intended cuz its tied to the device its being used rn. + // why + // and in ALC.EVENT_TYPE_DEFAULT_DEVICE_CHANGED_SOFT, deviceName is the device GUID + @:noCompletion private static function __deviceEventCallback(eventType:Int, deviceType:Int, device:ALDevice, + deviceName:String, message:String) + { + var currentContext = ALC.getCurrentContext(); + var currentDevice = currentContext != null ? ALC.getContextsDevice(currentContext) : null; + if (deviceType == ALC.PLAYBACK_DEVICE_SOFT) { + switch (eventType) { + case ALC.EVENT_TYPE_DEFAULT_DEVICE_CHANGED_SOFT: + if (automaticDefaultPlaybackDevice) refresh(); + onDefaultPlaybackDeviceChanged.dispatch(getPlaybackDefaultDeviceName()); + case ALC.EVENT_TYPE_DEVICE_ADDED_SOFT: + onPlaybackDeviceAdded.dispatch(__formatDeviceName(deviceName)); + case ALC.EVENT_TYPE_DEVICE_REMOVED_SOFT: + if (__disconnectExtSupported && ALC.getIntegerv(currentDevice, ALC.CONNECTED, 1)[0] != 1) refresh(); + onPlaybackDeviceRemoved.dispatch(__formatDeviceName(deviceName)); + } + } + else if (deviceType == ALC.CAPTURE_DEVICE_SOFT) { + switch (eventType) { + case ALC.EVENT_TYPE_DEFAULT_DEVICE_CHANGED_SOFT: + onDefaultCaptureDeviceChanged.dispatch(getCaptureDefaultDeviceName()); + case ALC.EVENT_TYPE_DEVICE_ADDED_SOFT: + onCaptureDeviceAdded.dispatch(__formatDeviceName(deviceName)); + case ALC.EVENT_TYPE_DEVICE_REMOVED_SOFT: + onCaptureDeviceRemoved.dispatch(__formatDeviceName(deviceName)); + } + } + } + + @:noCompletion private static function __refresh():Void + { + if (context == null || context.type != OPENAL) return; + + 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'); + __reopenDeviceSupported = ALC.isExtensionPresent(null, 'ALC_SOFT_reopen_device'); + __systemEventsSupported = ALC.isExtensionPresent(null, 'ALC_SOFT_system_events'); + __enumerateAllSupported = ALC.isExtensionPresent(null, 'ALC_ENUMERATE_ALL_EXT'); + + __latencyExtensionSupported = AL.isExtensionPresent('AL_SOFT_source_latency'); + __loopPointsSupported = AL.isExtensionPresent('AL_SOFT_loop_points'); + __moreFormatsSupported = AL.isExtensionPresent('AL_EXT_MCFORMATS'); + __spatializeSupported = AL.isExtensionPresent('AL_SOFT_source_spatialize'); + __stereoAnglesSupported = AL.isExtensionPresent('AL_EXT_STEREO_ANGLES'); + } + + @:noCompletion private static function __formatDeviceName(deviceName:String) + { + if (StringTools.startsWith(deviceName, 'OpenAL Soft on ')) return deviceName.substr(15); + else if (StringTools.startsWith(deviceName, 'OpenAL on ')) return deviceName.substr(10); + else if (StringTools.startsWith(deviceName, 'Generic Software on ')) return deviceName.substr(20); + else return deviceName; + } + + // permanent band-aid fix whatever + @: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 __alDeviceEventCallback(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); + __alRequestEvents.add({eventType: eventType, deviceType: deviceType, device: device, deviceName: deviceName, message: message}); + } + #end +} + +#if (lime_openal && !lime_doc_gen) +private typedef ALDeviceEvent = +{ + eventType:Int, + deviceType:Int, + device:Null, + deviceName:Null, + message:String } +#end \ No newline at end of file diff --git a/src/lime/media/openal/AL.hx b/src/lime/media/openal/AL.hx index ee5b02469e..7aaacedf64 100644 --- a/src/lime/media/openal/AL.hx +++ b/src/lime/media/openal/AL.hx @@ -232,15 +232,43 @@ class AL public static inline var FILTER_LOWPASS:Int = 0x0001; public static inline var FILTER_HIGHPASS:Int = 0x0002; public static inline var FILTER_BANDPASS:Int = 0x0003; - - public static inline var STOP_SOURCES_ON_DISCONNECT_SOFT:Int = 0x19AB; - - public static inline var DEVICE_CLOCK_SOFT:Int = 0x1600; - public static inline var DEVICE_LATENCY_SOFT:Int = 0x1601; - public static inline var DEVICE_CLOCK_LATENCY_SOFT:Int = 0x1602; - + /* AL_EXT_float32 */ + public static inline var FORMAT_MONO_FLOAT32:Int = 0x10010; + public static inline var FORMAT_STEREO_FLOAT32:Int = 0x10011; + /* UNKNOWN */ + public static inline var FORMAT_MONO32:Int = 0x1202; + public static inline var FORMAT_STEREO32:Int = 0x1203; + /* AL_EXT_MCFORMATS */ + public static inline var FORMAT_QUAD8:Int = 0x1204; + public static inline var FORMAT_QUAD16:Int = 0x1205; + public static inline var FORMAT_QUAD32:Int = 0x1206; + public static inline var FORMAT_REAR8:Int = 0x1207; + public static inline var FORMAT_REAR16:Int = 0x1208; + public static inline var FORMAT_REAR32:Int = 0x1209; + public static inline var FORMAT_51CHN8:Int = 0x120A; + public static inline var FORMAT_51CHN16:Int = 0x120B; + public static inline var FORMAT_51CHN32:Int = 0x120C; + public static inline var FORMAT_61CHN8:Int = 0x120D; + public static inline var FORMAT_61CHN16:Int = 0x120E; + public static inline var FORMAT_61CHN32:Int = 0x120F; + public static inline var FORMAT_71CHN8:Int = 0x1210; + public static inline var FORMAT_71CHN16:Int = 0x1211; + public static inline var FORMAT_71CHN32:Int = 0x1212; + /* AL_SOFT_loop_points */ + public static inline var LOOP_POINTS_SOFT:Int = 0x2015; + /* AL_EXT_STEREO_ANGLES */ + public static inline var STEREO_ANGLES:Int = 0x1030; + /* AL_SOFT_source_latency */ + public static inline var SAMPLE_OFFSET_LATENCY_SOFT:Int = 0x1200; public static inline var SEC_OFFSET_LATENCY_SOFT:Int = 0x1201; + /* AL_SOFT_source_spatialize */ + public static inline var SOURCE_SPATIALIZE_SOFT:Int = 0x1214; + public static inline var AUTO_SOFT:Int = 0x0002; + /* ALC_SOFT_device_clock */ + public static inline var SAMPLE_OFFSET_CLOCK_SOFT:Int = 0x1202; public static inline var SEC_OFFSET_CLOCK_SOFT:Int = 0x1203; + /* AL_SOFT_hold_on_disconnect */ + public static inline var STOP_SOURCES_ON_DISCONNECT_SOFT:Int = 0x19AB; public static function removeDirectFilter(source:ALSource) { @@ -442,6 +470,25 @@ class AL #end } + public static function deleteEffect(effect:ALEffect):Void + { + #if (lime_cffi && lime_openal && !macro) + NativeCFFI.lime_al_delete_effect(effect); + #end + } + + public static function deleteFilter(filter:ALFilter):Void { + #if (lime_cffi && lime_openal && !macro) + NativeCFFI.lime_al_delete_filter(filter); + #end + } + + public static function deleteAux(aux:ALAuxiliaryEffectSlot):Void { + #if (lime_cffi && lime_openal && !macro) + NativeCFFI.lime_al_delete_auxiliary_effect_slot(aux); + #end + } + public static function disable(capability:Int):Void { #if (lime_cffi && lime_openal && !macro) diff --git a/src/lime/media/openal/ALC.hx b/src/lime/media/openal/ALC.hx index 81fd0d32f3..e1349438c0 100644 --- a/src/lime/media/openal/ALC.hx +++ b/src/lime/media/openal/ALC.hx @@ -25,14 +25,28 @@ class ALC public static inline var INVALID_ENUM:Int = 0xA003; public static inline var INVALID_VALUE:Int = 0xA004; public static inline var OUT_OF_MEMORY:Int = 0xA005; + public static inline var MAJOR_VERSION:Int = 0x1000; + public static inline var MINOR_VERSION:Int = 0x1001; public static inline var ATTRIBUTES_SIZE:Int = 0x1002; public static inline var ALL_ATTRIBUTES:Int = 0x1003; + /* ALC_ENUMERATION_EXT */ public static inline var DEFAULT_DEVICE_SPECIFIER:Int = 0x1004; public static inline var DEVICE_SPECIFIER:Int = 0x1005; public static inline var EXTENSIONS:Int = 0x1006; - public static inline var ENUMERATE_ALL_EXT:Int = 1; + /* ALC_EXT_CAPTURE */ + public static inline var CAPTURE_DEVICE_SPECIFIER:Int = 0x310; + public static inline var CAPTURE_DEFAULT_DEVICE_SPECIFIER:Int = 0x311; + public static inline var CAPTURE_SAMPLES:Int = 0x312; + /* ALC_ENUMERATE_ALL_EXT */ public static inline var DEFAULT_ALL_DEVICES_SPECIFIER:Int = 0x1012; public static inline var ALL_DEVICES_SPECIFIER:Int = 0x1013; + /* ALC_EXT_disconnect */ + public static inline var CONNECTED:Int = 0x313; + /* ALC_SOFT_device_clock */ + public static inline var DEVICE_CLOCK_SOFT:Int = 0x1600; + public static inline var DEVICE_LATENCY_SOFT:Int = 0x1601; + public static inline var DEVICE_CLOCK_LATENCY_SOFT:Int = 0x1602; + /* ALC_SOFT_system_events */ public static inline var PLAYBACK_DEVICE_SOFT:Int = 0x19D4; public static inline var CAPTURE_DEVICE_SOFT:Int = 0x19D5; public static inline var EVENT_TYPE_DEFAULT_DEVICE_CHANGED_SOFT:Int = 0x19D6; @@ -159,6 +173,24 @@ class ALC #end } + public static function getStringList(device:ALDevice, param:Int):Array + { + #if (lime_cffi && lime_openal && !macro) + var result = NativeCFFI.lime_alc_get_string_list(device, param); + #if hl + if (result == null) return []; + var _result = []; + for (i in 0...result.length) + _result[i] = CFFI.stringValue(result[i]); + return _result; + #else + return result; + #end + #else + return null; + #end + } + public static function makeContextCurrent(context:ALContext):Bool { #if (lime_cffi && lime_openal && !macro)