11package lime .media ;
22
3- import lime .system .CFFIPointer ;
43import haxe .MainLoop ;
5- import haxe .Timer ;
6- import lime ._internal .backend .native .NativeCFFI ;
4+ import lime .app .Event ;
5+ import lime .system .CFFIPointer ;
6+ import lime .system .System ;
7+ #if lime_openal
78import lime .media .openal .AL ;
89import lime .media .openal .ALC ;
910import lime .media .openal .ALContext ;
1011import lime .media .openal .ALDevice ;
11- import lime .app .Application ;
12- #if (js && html5)
13- import js .Browser ;
12+ #elseif lime_howlerjs
13+ import lime .media .howlerjs .Howler ;
1414#end
1515
1616#if !lime_debug
1717@:fileXml (' tags="haxe,release"' )
1818@:noDebug
1919#end
20- @:access (lime._internal.backend.native. NativeCFFI )
2120@:access (lime.media.openal. ALDevice )
2221class AudioManager
2322{
23+ /**
24+ The current used context to use for the audio manager.
25+ **/
2426 public static var context : AudioContext ;
2527
28+ #if lime_openal
29+ @:noCompletion private static var __disconnectExtSupported : Bool ;
30+ @:noCompletion private static var __reopenDeviceSupported : Bool ;
31+ @:noCompletion private static var __systemEventsSupported : Bool ;
32+ #end
33+
34+ /**
35+ Initializes an `AudioManager` to playback to and capture from audio devices.
36+ Automatically dispatched when Application is constructed.
37+
38+ @param context Optional; An Audio Context to initalize the `AudioManager` with.
39+ **/
2640 public static function init (context : AudioContext = null )
2741 {
28- if (AudioManager .context == null )
42+ if (AudioManager .context != null ) return ;
43+
44+ if (context == null )
2945 {
30- if (context == null )
31- {
32- AudioManager .context = new AudioContext ();
46+ context = new AudioContext ();
47+ }
3348
34- context = AudioManager . context ;
49+ AudioManager . context = context ;
3550
36- #if !lime_doc_gen
37- if (context .type == OPENAL )
38- {
39- var alc = context .openal ;
40- var device = alc .openDevice ();
41- var ctx = alc .createContext (device );
51+ #if lime_openal
52+ if (context .type == OPENAL )
53+ {
54+ refresh ();
4255
43- alc .makeContextCurrent (ctx );
44- alc .processContext (ctx );
56+ #if !(neko || mobile)
57+ if (__reopenDeviceSupported ) AL .disable (AL .STOP_SOURCES_ON_DISCONNECT_SOFT );
58+ if (__systemEventsSupported ) {
59+ ALC .eventControlSOFT ([
60+ ALC .EVENT_TYPE_DEFAULT_DEVICE_CHANGED_SOFT ,
61+ ALC .EVENT_TYPE_DEVICE_ADDED_SOFT ,
62+ ALC .EVENT_TYPE_DEVICE_REMOVED_SOFT ],
63+ true );
64+ ALC .eventCallbackSOFT (__deviceEventCallback );
65+ }
66+ #end
67+ }
68+ #end
69+ }
4570
46- #if !(neko || mobile)
47- if (alc .isExtensionPresent (' ALC_SOFT_system_events' , device ) && alc .isExtensionPresent (' ALC_SOFT_reopen_device' , device ))
48- {
49- alc .disable (AL .STOP_SOURCES_ON_DISCONNECT_SOFT );
71+ /**
72+ Refresh the context with optionally to different device.
5073
51- alc . eventControlSOFT ([ ALC . EVENT_TYPE_DEFAULT_DEVICE_CHANGED_SOFT , ALC . EVENT_TYPE_DEVICE_ADDED_SOFT , ALC . EVENT_TYPE_DEVICE_REMOVED_SOFT ], true );
74+ Only works on Native target.
5275
53- alc . eventCallbackSOFT ( deviceEventCallback );
54- }
55- #end
56- }
57- #end
58- }
76+ @param deviceName Optional; The device name to use to for playbacking the audios.
77+ * */
78+ public static function refresh ( ? deviceName : String ) : Bool
79+ {
80+ #if (lime_openal && !lime_doc_gen)
81+ if ( context == null || context . type != OPENAL ) return false ;
5982
60- AudioManager .context = context ;
83+ var currentContext = ALC .getCurrentContext ();
84+ var device = currentContext != null ? ALC .getContextsDevice (currentContext ) : null ;
85+
86+ if (device != null && __reopenDeviceSupported && ALC .reopenDeviceSOFT (device , deviceName , null ))
87+ {
88+ __refresh ();
89+ return true ;
90+ }
91+
92+ if (currentContext != null )
93+ {
94+ ALC .destroyContext (currentContext );
95+ currentContext = null ;
96+ }
97+
98+ if (device != null )
99+ {
100+ ALC .closeDevice (device );
101+ device = null ;
61102 }
103+
104+ if ((device = ALC .openDevice ()) == null || (currentContext = ALC .createContext (device )) == null
105+ || ! ALC .makeContextCurrent (currentContext ))
106+ {
107+ return false ;
108+ }
109+
110+ ALC .processContext (currentContext );
111+ __refresh ();
112+ return true ;
113+ #else
114+ return false ;
115+ #end
62116 }
63117
118+ /**
119+ Resumes the current `AudioManager` context.
120+
121+ This function does not work on the Flash target.
122+ **/
64123 public static function resume (): Void
65124 {
66- #if !lime_doc_gen
125+ #if (lime_openal && !lime_doc_gen)
67126 if (context != null && context .type == OPENAL )
68127 {
69- var alc = context .openal ;
70- var currentContext = alc .getCurrentContext ();
71-
128+ var currentContext = ALC .getCurrentContext ();
72129 if (currentContext != null )
73130 {
74- var device = alc .getContextsDevice (currentContext );
75- alc .resumeDevice (device );
76- alc .processContext (currentContext );
131+ var device = ALC .getContextsDevice (currentContext );
132+ if (device != null ) ALC .resumeDevice (device );
133+
134+ ALC .processContext (currentContext );
77135 }
78136 }
137+ #elseif (js && html5)
138+ if (context != null && context .type == WEB )
139+ {
140+ context .web .resume ();
141+ }
79142 #end
80143 }
81144
145+ /**
146+ Shutdowns the current `AudioManager` context.
147+
148+ This function does not work on the Flash target.
149+ **/
82150 public static function shutdown (): Void
83151 {
84- #if !lime_doc_gen
152+ #if (lime_openal && !lime_doc_gen)
85153 if (context != null && context .type == OPENAL )
86154 {
87- var alc = context .openal ;
88- var currentContext = alc .getCurrentContext ();
89- var device = alc .getContextsDevice (currentContext );
90-
155+ var currentContext = ALC .getCurrentContext ();
91156 if (currentContext != null )
92157 {
93- alc .makeContextCurrent (null );
94- alc .destroyContext (currentContext );
158+ ALC .makeContextCurrent (null );
159+ ALC .destroyContext (currentContext );
95160
96- if (device != null )
97- {
98- alc .closeDevice (device );
99- }
161+ var device = ALC .getContextsDevice (currentContext );
162+ if (device != null ) ALC .closeDevice (device );
100163 }
101164 }
165+ #elseif (js && html5)
166+ if (context != null && context .type == WEB )
167+ {
168+ #if lime_howlerjs
169+ Howler .unload ();
170+ #else
171+ context .web .close ();
172+ #end
173+ }
102174 #end
103175
104176 context = null ;
105177 }
106178
179+ /**
180+ Pauses the current `AudioManager` context.
181+
182+ This function does not work on the Flash target.
183+ **/
107184 public static function suspend (): Void
108185 {
109- #if !lime_doc_gen
186+ #if (lime_openal && !lime_doc_gen)
110187 if (context != null && context .type == OPENAL )
111188 {
112- var alc = context .openal ;
113- var currentContext = alc .getCurrentContext ();
114- var device = alc .getContextsDevice (currentContext );
115-
189+ var currentContext = ALC .getCurrentContext ();
116190 if (currentContext != null )
117191 {
118- alc .suspendContext (currentContext );
192+ ALC .suspendContext (currentContext );
119193
120- if (device != null )
121- {
122- alc .pauseDevice (device );
123- }
194+ var device = ALC .getContextsDevice (currentContext );
195+ if (device != null ) ALC .pauseDevice (device );
124196 }
125197 }
198+ #elseif (js && html5)
199+ if (context != null && context .type == WEB )
200+ {
201+ context .web .suspend ();
202+ }
126203 #end
127204 }
128205
129- @:noCompletion
130- #if hl
131- private static function deviceEventCallback (eventType : Int , deviceType : Int , handle : CFFIPointer , message : hl. Bytes ): Void
132- #else
133- private static function deviceEventCallback (eventType : Int , deviceType : Int , handle : CFFIPointer , message : String ): Void
134- #end
206+ #if (lime_openal && !lime_doc_gen)
207+ // device is null... and its actually intended cuz its tied to the device its being used rn.
208+ // why
209+ // and in ALC.EVENT_TYPE_DEFAULT_DEVICE_CHANGED_SOFT, deviceName is the device GUID
210+ #if !(neko || mobile)
211+ @:noCompletion private static function __deviceEventCallback (eventType : Int , deviceType : Int , handle : CFFIPointer ,
212+ #if hl _message : hl. Bytes #else message:String #end)
135213 {
136- #if !lime_doc_gen
137- if (eventType == ALC .EVENT_TYPE_DEFAULT_DEVICE_CHANGED_SOFT && deviceType == ALC .PLAYBACK_DEVICE_SOFT )
138- {
139- var device = new ALDevice (handle );
214+ #if hl var message : String = CFFI .stringValue (_message ); #end
215+ var device : ALDevice = handle != null ? new ALDevice (handle ) : null ;
216+ var deviceName = __getDeviceNameFromMessage (message );
140217
141- MainLoop .runInMainThread (function (): Void
142- {
143- var alc = context .openal ;
218+ var currentContext = ALC .getCurrentContext ();
219+ var currentDevice = currentContext != null ? ALC .getContextsDevice (currentContext ) : null ;
220+ if (deviceType == ALC .PLAYBACK_DEVICE_SOFT ) {
221+ switch (eventType ) {
222+ case ALC .EVENT_TYPE_DEFAULT_DEVICE_CHANGED_SOFT :
223+ refresh ();
224+ case ALC .EVENT_TYPE_DEVICE_ADDED_SOFT :
144225
145- if (device == null )
146- {
147- var currentContext = alc .getCurrentContext ();
226+ case ALC .EVENT_TYPE_DEVICE_REMOVED_SOFT :
227+ if (__disconnectExtSupported && ALC .getIntegerv (currentDevice , ALC .CONNECTED , 1 )[0 ] != 1 ) refresh ();
228+ }
229+ }
230+ else if (deviceType == ALC .CAPTURE_DEVICE_SOFT ) {
231+ switch (eventType ) {
232+ case ALC .EVENT_TYPE_DEFAULT_DEVICE_CHANGED_SOFT :
148233
149- var device = alc . getContextsDevice ( currentContext );
234+ case ALC . EVENT_TYPE_DEVICE_ADDED_SOFT :
150235
151- if (device != null )
152- alc .reopenDeviceSOFT (device , null , null );
153- }
154- else
155- {
156- alc .reopenDeviceSOFT (device , null , null );
157- }
236+ case ALC .EVENT_TYPE_DEVICE_REMOVED_SOFT :
158237
159- });
238+ }
160239 }
161- #end
162240 }
163- }
241+ #end
242+
243+ @:noCompletion private static function __refresh (): Void
244+ {
245+ if (context == null || context .type != OPENAL ) return ;
246+
247+ var currentContext = ALC .getCurrentContext ();
248+ if (currentContext == null ) return ;
249+
250+ var device = ALC .getContextsDevice (currentContext );
251+ if (device == null ) return ;
252+
253+ __disconnectExtSupported = ALC .isExtensionPresent (null , ' ALC_EXT_disconnect' );
254+ __reopenDeviceSupported = ALC .isExtensionPresent (null , ' ALC_SOFT_reopen_device' );
255+ __systemEventsSupported = ALC .isExtensionPresent (null , ' ALC_SOFT_system_events' );
256+ }
257+
258+ // permanent band-aid fix whatever
259+ @:noCompletion private static function __getDeviceNameFromMessage (message : String ): Null <String >
260+ {
261+ if (StringTools .startsWith (message , ' Device removed: ' )) return message .substr (16 );
262+ else if (StringTools .startsWith (message , ' Device added: ' )) return message .substr (14 );
263+ else return null ;
264+ }
265+ #end
266+ }
0 commit comments