JOAL v2.6.0-rc-20250706
JOAL, OpenAL® API Binding for Java™ (public API).
Context.java
Go to the documentation of this file.
1/**
2* Copyright (c) 2010-2023 JogAmp Community. All rights reserved.
3* Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
4*
5* Redistribution and use in source and binary forms, with or without
6* modification, are permitted provided that the following conditions are met:
7*
8* -Redistribution of source code must retain the above copyright notice,
9* this list of conditions and the following disclaimer.
10*
11* -Redistribution in binary form must reproduce the above copyright notice,
12* this list of conditions and the following disclaimer in the documentation
13* and/or other materials provided with the distribution.
14*
15* Neither the name of Sun Microsystems, Inc. or the names of contributors may
16* be used to endorse or promote products derived from this software without
17* specific prior written permission.
18*
19* This software is provided "AS IS," without a warranty of any kind.
20* ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
21* ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
22* NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS
23* LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A
24* RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
25* IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT
26* OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
27* PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
28* ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS
29* BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
30*
31* You acknowledge that this software is not designed or intended for use in the
32* design, construction, operation or maintenance of any nuclear facility.
33*/
34
35package com.jogamp.openal.sound3d;
36
37import com.jogamp.common.util.locks.Lock;
38import com.jogamp.common.util.locks.LockFactory;
39import com.jogamp.common.util.locks.RecursiveLock;
40import com.jogamp.openal.*;
41import com.jogamp.openal.util.ALHelpers;
42
43
44/**
45 * This class provides a Sound3D Context associated with a specified device.
46 *
47 * @author Athomas Goldberg, Sven Gothel, et al.
48 */
49public final class Context {
50 private final RecursiveLock lock = LockFactory.createRecursiveLock();
51 private final Device device;
52 private volatile ALCcontext alCtx;
53 private boolean threadContextLocked;
54 public final boolean hasALC_thread_local_context;
55 private static final ThreadLocal<Context> currentContext = new ThreadLocal<Context>();
56
57 /**
58 * Creates a new Context for a given {@link ALCcontext} for the specified device.
59 *
60 * @param realContext {@link ALCcontext} instance, maybe null
61 * @param device The device the Context belongs to, must be valid
62 */
63 public Context(final ALCcontext realContext, final Device device) {
64 this.device = device;
65 this.alCtx = realContext;
66 {
67 final boolean v;
68 if( makeCurrent(false) ) {
71 release(false);
72 } else {
73 v = false;
74 }
76 }
77 }
78
79 /**
80 * Creates a new Context for a specified device including native {@link ALCcontext} creation.
81 *
82 * @param device The device the Context is being created for, must be valid.
83 * @param attributes list of {@link ALCcontext} attributes for context creation, maybe empty or null
84 */
85 public Context(final Device device, final int[] attributes) {
86 this( createImpl(device.getALDevice(), attributes), device);
87 }
88
89 /**
90 * Creates a new {@link ALCcontext}.
91 *
92 * @param alDevice a valid {@link ALCdevice}
93 * @param attributes lost of {@link ALCcontext} attributes for context creation
94 */
95 private static ALCcontext createImpl(final ALCdevice alDevice, final int[] attributes) {
96 if( null != attributes && attributes.length > 0 ) {
97 return AudioSystem3D.alc.alcCreateContext(alDevice, attributes, 0);
98 } else {
99 return AudioSystem3D.alc.alcCreateContext(alDevice, null);
100 }
101 }
102
103 /**
104 * Returns whether `AL_EXT_debug` is available for the current context.
105 * @see Device#isDebugAvail()
106 */
107 public boolean isDebugAvail() {
109 }
110
111 /**
112 * Creates the internal {@link ALCcontext} instance if {@link #getALContext()} is null
113 * @param attributes lost of {@link ALCcontext} attributes for context creation
114 * @return true if the internal context has been successfully created, otherwise false
115 */
116 public boolean create(final int[] attributes) {
117 lock.lock();
118 try {
119 if( null == alCtx ) {
120 alCtx = createImpl(device.getALDevice(), attributes);
121 return null != alCtx;
122 }
123 return false;
124 } finally {
125 lock.unlock();
126 }
127 }
128
129 /**
130 * Recreates the internal {@link ALCcontext} instance, i.e. destroys it first if {@link #getALContext()} not null.
131 * <p>
132 * Context is made current again if it was current before.
133 * </p>
134 * @param attributes lost of {@link ALCcontext} attributes for context creation
135 * @return true if the internal context has been successfully recreated and made current again if was current before, otherwise false
136 */
137 public boolean recreate(final int[] attributes) {
138 lock.lock();
139 try {
140 final boolean wasCurrent = this == getCurrentContext();
141 destroyImpl();
142 alCtx = createImpl(device.getALDevice(), attributes);
143 if( null != alCtx ) {
144 if( wasCurrent ) {
145 return makeCurrentImpl();
146 } else {
147 return false;
148 }
149 } else {
150 return false;
151 }
152 } finally {
153 lock.unlock();
154 }
155 }
156
157 /** Returns the OpenAL {@link ALCcontext}. */
158 public ALCcontext getALContext() { return alCtx; }
159
160 /** Returns whether {@link #getALContext()} is valid, i.e. not null, e.g. not {@link #destroy()}'ed. */
161 public boolean isValid() { return null != alCtx; }
162
163 /** Return {@link ALC#alcGetError(ALCdevice)} using {@link #getDevice()}. */
164 public int getALCError() {
165 return device.getALCError();
166 }
167
168 /**
169 * destroys this context freeing its resources.
170 */
171 public void destroy() {
172 lock.lock();
173 try {
174 destroyImpl();
175 if( currentContext.get() == this ) {
176 currentContext.set(null);
177 }
178 // unroll lock !
179 while(lock.getHoldCount() > 1) {
180 lock.unlock();
181 }
182 } finally {
183 lock.unlock();
184 }
185 }
186 private void destroyImpl() {
187 if( null != alCtx ) {
188 if( threadContextLocked ) {
190 } else {
191 AudioSystem3D.alc.alcMakeContextCurrent(null);
192 }
193 AudioSystem3D.alc.alcDestroyContext(alCtx);
194 alCtx = null;
195 }
196 }
197
198 /**
199 * Returns this thread current context.
200 * If no context is current, returns null.
201 *
202 * @return the context current on this thread, or null if no context is current.
203 * @see #makeCurrent()
204 * @see #release()
205 */
206 public static Context getCurrentContext() {
207 return currentContext.get();
208 }
209
210 /** Return the lock count of this context, i.e. 0 if not locked, 1 if locked once, >1 for recursive locks. */
211 public int getLockCount() {
212 return lock.getHoldCount();
213 }
214
215 public boolean tryMakeCurrent(final boolean throwException, final long timeoutMS) throws RuntimeException {
216 return makeCurrentImpl(false /* throwTryLockException */, throwException, timeoutMS);
217 }
218 /**
219 * Makes the audio context current on the calling thread.
220 * <p>
221 * Recursive call to {@link #makeCurrent()} and hence {@link #release()} are supported.
222 * </p>
223 * <p>
224 * At any point in time one context can only be current on one thread,
225 * and one thread can only have one context current.
226 * </p>
227 * @param throwException if true, throws ALException if {@link #getALContext()} is null, current thread holds another context or failed to natively make current
228 * @return true if {@link #getALContext()} is valid, current thread holds no other context and context successfully made current, otherwise false
229 * @see #release()
230 */
231 public boolean makeCurrent(final boolean throwException) throws ALException {
232 return makeCurrentImpl(true /* throwTryLockException */, throwException, Lock.TIMEOUT);
233 }
234 private boolean makeCurrentImpl(final boolean throwTryLockException, final boolean throwException, final long timeoutMS) throws RuntimeException {
235 try {
236 if( lock.tryLock(timeoutMS) ) {
237 if( null == alCtx ) {
238 lock.unlock();
239 if( throwException ) {
240 throw new ALException("Invalid "+this);
241 }
242 return false;
243 }
244
245 // One context can only be current on one thread,
246 // and one thread can only have one context current!
247 final Context current = getCurrentContext();
248 if (current != null) {
249 if (current == this) { // implicit recursive locking, lock.getHoldCount() > 1
250 return true;
251 } else {
252 lock.unlock();
253 if( throwException ) {
254 throw new ALException("Current thread "+Thread.currentThread()+" holds another "+current+" while claiming this "+this);
255 }
256 return false;
257 }
258 }
259 final boolean r = makeCurrentImpl();
260 if( r ) {
261 currentContext.set(this);
262 } else {
263 lock.unlock();
264 if( throwException ) {
265 throw new ALException("Context make current failed "+this);
266 }
267 }
268 return r;
269 } else {
270 if( throwTryLockException ) {
271 throw new RuntimeException("Waited "+timeoutMS+"ms for: "+lock.toString()+" - "+Thread.currentThread().getName());
272 }
273 return false;
274 }
275 } catch (final InterruptedException ie) {
276 throw new RuntimeException(ie);
277 }
278 }
279 private boolean makeCurrentImpl() {
281 threadContextLocked = true;
282 return AudioSystem3D.alExt.alcSetThreadContext(alCtx);
283 } else {
284 threadContextLocked = false;
285 return AudioSystem3D.alc.alcMakeContextCurrent(alCtx);
286 }
287 }
288
289 /**
290 * Releases control of this audio context from the current thread, if implementation utilizes context locking.
291 * <p>
292 * Recursive call to {@link #makeCurrent()} and hence {@link #release()} are supported.
293 * </p>
294 * <p>
295 * If native release fails, internal lock is not released.
296 * </p>
297 * @param throwException if true, throws ALException if context has not been previously made current on current thread
298 * or native release failed.
299 * @return true if context has previously been made current on the current thread and successfully released, otherwise false
300 * @see #makeCurrent()
301 */
302 public boolean release(final boolean throwException) throws ALException {
303 if( !lock.isOwner( Thread.currentThread() ) ) {
304 if( throwException ) {
305 throw new ALException("Context not held on current thread "+Thread.currentThread()+", "+this);
306 }
307 return false;
308 }
309 if( lock.getHoldCount() == 1 ) {
310 final boolean r;
311 if( threadContextLocked ) {
312 r = AudioSystem3D.alExt.alcSetThreadContext(null);
313 } else {
315 }
316 if( r ) {
317 currentContext.set(null);
318 } else {
319 if( throwException ) {
320 throw new ALException("Context release failed "+this);
321 }
322 return false; // skip unlock!
323 }
324 }
325 lock.unlock();
326 return true;
327 }
328
329 /**
330 * Suspend this context
331 */
332 public void suspend() {
334 }
335
336 /**
337 * Gets the device associated with this context.
338 *
339 * @return the device associated with this context.
340 */
341 public Device getDevice() {
342 return device;
343 }
344
345 @Override
346 public String toString() {
347 final String alCtxStr = null != alCtx ? "0x"+Integer.toHexString(alCtx.hashCode()) : "null";
348 return "ALContext[this 0x"+Integer.toHexString(hashCode())+", alCtx "+alCtxStr+" lockCount "+lock.getHoldCount()+", on "+device+"]";
349 }
350}
A generic exception for OpenAL errors used throughout the binding as a substitute for RuntimeExceptio...
The AudioSystem3D class provides a set of methods for creating and manipulating a 3D audio environmen...
This class provides a Sound3D Context associated with a specified device.
Definition: Context.java:49
boolean release(final boolean throwException)
Releases control of this audio context from the current thread, if implementation utilizes context lo...
Definition: Context.java:302
boolean isValid()
Returns whether getALContext() is valid, i.e.
Definition: Context.java:161
boolean makeCurrent(final boolean throwException)
Makes the audio context current on the calling thread.
Definition: Context.java:231
int getALCError()
Return ALC#alcGetError(ALCdevice) using getDevice().
Definition: Context.java:164
int getLockCount()
Return the lock count of this context, i.e.
Definition: Context.java:211
void suspend()
Suspend this context.
Definition: Context.java:332
Context(final Device device, final int[] attributes)
Creates a new Context for a specified device including native ALCcontext creation.
Definition: Context.java:85
boolean isDebugAvail()
Returns whether AL_EXT_debug is available for the current context.
Definition: Context.java:107
boolean recreate(final int[] attributes)
Recreates the internal ALCcontext instance, i.e.
Definition: Context.java:137
Device getDevice()
Gets the device associated with this context.
Definition: Context.java:341
void destroy()
destroys this context freeing its resources.
Definition: Context.java:171
boolean tryMakeCurrent(final boolean throwException, final long timeoutMS)
Definition: Context.java:215
Context(final ALCcontext realContext, final Device device)
Creates a new Context for a given ALCcontext for the specified device.
Definition: Context.java:63
ALCcontext getALContext()
Returns the OpenAL ALCcontext.
Definition: Context.java:158
boolean create(final int[] attributes)
Creates the internal ALCcontext instance if getALContext() is null.
Definition: Context.java:116
final boolean hasALC_thread_local_context
Definition: Context.java:54
static Context getCurrentContext()
Returns this thread current context.
Definition: Context.java:206
This class provides a handle to a specific audio device.
Definition: Device.java:46
int getALCError()
Return ALC#alcGetError(ALCdevice).
Definition: Device.java:68
ALCdevice getALDevice()
Returns the OpenAL ALCdevice.
Definition: Device.java:65
static final String ALC_EXT_thread_local_context
Definition: ALHelpers.java:53
static final String AL_EXT_debug
Definition: ALHelpers.java:59
boolean alcMakeContextCurrent(ALCcontext context)
Entry point (through function pointer) to C language function: ALCboolean alcMakeContextCurrent(ALC...
void alcSuspendContext(ALCcontext context)
Entry point (through function pointer) to C language function: void alcSuspendContext(ALCcontext * ...
boolean alcIsExtensionPresent(ALCdevice device, String extname)
Entry point (through function pointer) to C language function: ALCboolean alcIsExtensionPresent(ALC...
ALCcontext alcCreateContext(ALCdevice device, IntBuffer attrlist)
Entry point (through function pointer) to C language function: ALCcontext * alcCreateContext(ALCdev...
boolean alcSetThreadContext(ALCcontext context)
Entry point (through function pointer) to C language function: ALCboolean alcSetThreadContext(ALCco...
boolean alIsExtensionPresent(String extname)
Entry point (through function pointer) to C language function: ALboolean alIsExtensionPresent(const...