diff --git a/src/java/org/lwjgl/openal/AL.java b/src/java/org/lwjgl/openal/AL.java index a185f34f..5022520e 100644 --- a/src/java/org/lwjgl/openal/AL.java +++ b/src/java/org/lwjgl/openal/AL.java @@ -31,15 +31,15 @@ */ package org.lwjgl.openal; -import java.util.Vector; - import org.lwjgl.LWJGLException; import org.lwjgl.LWJGLUtil; import org.lwjgl.Sys; /** - *
- * This is the OpenAL class. It extends the latest core. + *

+ * The AL class implements the actual creation code for linking to the native library + * OpenAL. + *

* * @author Brian Matzon * @version $Revision$ @@ -108,7 +108,7 @@ public final class AL { * @param openDevice Whether to automatically open the device * @see #create(String, int, int, boolean) */ - static void create(String deviceArguments, int contextFrequency, int contextRefresh, boolean contextSynchronized, boolean openDevice) + public static void create(String deviceArguments, int contextFrequency, int contextRefresh, boolean contextSynchronized, boolean openDevice) throws LWJGLException { if (created) @@ -196,6 +196,7 @@ public final class AL { */ public static void destroy() { if (context != null) { + ALC10.alcMakeContextCurrent(null); ALC10.alcDestroyContext(context); context = null; } diff --git a/src/java/org/lwjgl/openal/ALC10.java b/src/java/org/lwjgl/openal/ALC10.java index cc2443cc..ac66dcfd 100644 --- a/src/java/org/lwjgl/openal/ALC10.java +++ b/src/java/org/lwjgl/openal/ALC10.java @@ -33,16 +33,12 @@ package org.lwjgl.openal; import java.nio.Buffer; import java.nio.IntBuffer; +import java.util.HashMap; import org.lwjgl.BufferChecks; import org.lwjgl.LWJGLException; /** - * - *

- * This is the context class for OpenAL. This class implements functions - * in alc.h - *

* *

* ALC introduces the notion of a Device. A Device can be, depending on the @@ -54,19 +50,18 @@ import org.lwjgl.LWJGLException; * specifiers (represented as strings). *

* - *

- * NOTE:
- * The LWJGL implementation of OpenAL does not expose the device, nor the context. - * Whenever AL is created using the create method, an underlying - * device and context is created. Thus more advanced usage of multiple contexts and/or devices - * are not possible. The above mentioned features are very rarely used in games. - *

- * * @author Brian Matzon * @version $Revision: 2286 $ * $Id: ALC.java 2286 2006-03-23 19:32:21 +0000 (to, 23 mar 2006) matzon $ */ public final class ALC10 { + + /** List of active contexts */ + static HashMap contexts = new HashMap(); + + /** List of active devices */ + static HashMap devices = new HashMap(); + /** Bad value */ public static final int ALC_INVALID = 0; @@ -158,10 +153,10 @@ public final class ALC10 { public static String alcGetString(ALCdevice device, int pname) { String result; result = nalcGetString(getDevice(device), pname); - Util.checkALCError(); + Util.checkALCError(device); return result; } - private native static String nalcGetString(long device, int pname); + native static String nalcGetString(long device, int pname); /** * The application can query ALC for information using an integer query function. @@ -186,9 +181,9 @@ public final class ALC10 { public static void alcGetInteger(ALCdevice device, int pname, IntBuffer integerdata) { BufferChecks.checkDirect(integerdata); nalcGetIntegerv(getDevice(device), pname, integerdata.remaining(), integerdata, integerdata.position()); - Util.checkALCError(); + Util.checkALCError(device); } - private native static void nalcGetIntegerv(long device, int pname, int size, Buffer integerdata, int offset); + native static void nalcGetIntegerv(long device, int pname, int size, Buffer integerdata, int offset); /** * The alcOpenDevice function allows the application (i.e. the client program) to @@ -203,9 +198,13 @@ public final class ALC10 { * @return opened device, or null */ public static ALCdevice alcOpenDevice(String devicename) { - long device = nalcOpenDevice(devicename); - if(device > 0) { - return new ALCdevice(device); + long device_address = nalcOpenDevice(devicename); + if(device_address != 0) { + ALCdevice device = new ALCdevice(device_address); + synchronized (ALC10.devices) { + devices.put(new Long(device_address), device); + } + return device; } return null; } @@ -221,7 +220,13 @@ public final class ALC10 { * @param device address of native device to close */ public static boolean alcCloseDevice(ALCdevice device) { - return nalcCloseDevice(getDevice(device)); + boolean result = nalcCloseDevice(getDevice(device)); + device.setInvalid(); + synchronized (devices) { + devices.remove(new Long(device.device)); + } + return result; + } native static boolean nalcCloseDevice(long device); @@ -241,16 +246,20 @@ public final class ALC10 { * @return New context, or null if creation failed */ public static ALCcontext alcCreateContext(ALCdevice device, IntBuffer attrList) { - long context = nalcCreateContext(getDevice(device), attrList); - Util.checkALCError(); + long context_address = nalcCreateContext(getDevice(device), attrList); + Util.checkALCError(device); - if(context > 0) { - return new ALCcontext(context); + if(context_address != 0) { + ALCcontext context = new ALCcontext(context_address); + synchronized (ALC10.contexts) { + contexts.put(new Long(context_address), context); + } + device.addContext(context); + return context; } - return null; } - private native static long nalcCreateContext(long device, IntBuffer attrList); + native static long nalcCreateContext(long device, IntBuffer attrList); /** * To make a Context current with respect to AL Operation (state changes by issueing @@ -269,7 +278,7 @@ public final class ALC10 { public static int alcMakeContextCurrent(ALCcontext context) { return nalcMakeContextCurrent(getContext(context)); } - public native static int nalcMakeContextCurrent(long context); + native static int nalcMakeContextCurrent(long context); /** * The current context is the only context accessible to state changes by AL commands @@ -285,7 +294,7 @@ public final class ALC10 { public static void alcProcessContext(ALCcontext context) { nalcProcessContext(getContext(context)); } - private native static void nalcProcessContext(long context); + native static void nalcProcessContext(long context); /** * The application can query for, and obtain an handle to, the current context for the @@ -294,13 +303,16 @@ public final class ALC10 { * @return Current ALCcontext */ public static ALCcontext alcGetCurrentContext() { - long context = nalcGetCurrentContext(); - if(context > 0) { - return new ALCcontext(context); + ALCcontext context = null; + long context_address = nalcGetCurrentContext(); + if(context_address != 0) { + synchronized (ALC10.contexts) { + context = (ALCcontext) ALC10.contexts.get(new Long(context_address)); + } } - return null; + return context; } - public native static long nalcGetCurrentContext(); + native static long nalcGetCurrentContext(); /** * The application can query for, and obtain an handle to, the device of a given context. @@ -309,13 +321,16 @@ public final class ALC10 { * @param ALCdevice associated with context */ public static ALCdevice alcGetContextsDevice(ALCcontext context) { - long device = nalcGetContextsDevice(getContext(context)); - if (device > 0) { - return new ALCdevice(device); + ALCdevice device = null; + long device_address = nalcGetContextsDevice(getContext(context)); + if (device_address != 0) { + synchronized (ALC10.devices) { + device = (ALCdevice) ALC10.devices.get(new Long(device_address)); + } } - return null; + return device; } - private native static long nalcGetContextsDevice(long context); + native static long nalcGetContextsDevice(long context); /** * The application can suspend any context from processing (including the current @@ -332,7 +347,7 @@ public final class ALC10 { public static void alcSuspendContext(ALCcontext context) { nalcSuspendContext(getContext(context)); } - private native static void nalcSuspendContext(long context); + native static void nalcSuspendContext(long context); /** * The correct way to destroy a context is to first release it using alcMakeCurrent and @@ -342,6 +357,7 @@ public final class ALC10 { */ public static void alcDestroyContext(ALCcontext context) { nalcDestroyContext(getContext(context)); + context.setInvalid(); } native static void nalcDestroyContext(long context); @@ -363,7 +379,7 @@ public final class ALC10 { public static int alcGetError(ALCdevice device) { return nalcGetError(getDevice(device)); } - private native static int nalcGetError(long device); + native static int nalcGetError(long device); /** * Verify that a given extension is available for the current context and the device it @@ -376,10 +392,10 @@ public final class ALC10 { */ public static boolean alcIsExtensionPresent(ALCdevice device, String extName) { boolean result = nalcIsExtensionPresent(getDevice(device), extName); - Util.checkALCError(); + Util.checkALCError(device); return result; } - private native static boolean nalcIsExtensionPresent(long device, String extName); + native static boolean nalcIsExtensionPresent(long device, String extName); /** * Enumeration/token values are device independend, but tokens defined for @@ -393,13 +409,14 @@ public final class ALC10 { */ public static int alcGetEnumValue(ALCdevice device, String enumName) { int result = nalcGetEnumValue(getDevice(device), enumName); - Util.checkALCError(); + Util.checkALCError(device); return result; } - private native static int nalcGetEnumValue(long device, String enumName); + native static int nalcGetEnumValue(long device, String enumName); static long getDevice(ALCdevice device) { if(device != null) { + Util.checkALCValidDevice(device); return device.device; } return 0L; @@ -407,6 +424,7 @@ public final class ALC10 { static long getContext(ALCcontext context) { if(context != null) { + Util.checkALCValidContext(context); return context.context; } return 0L; diff --git a/src/java/org/lwjgl/openal/ALC11.java b/src/java/org/lwjgl/openal/ALC11.java index 010e7baf..98553e4c 100644 --- a/src/java/org/lwjgl/openal/ALC11.java +++ b/src/java/org/lwjgl/openal/ALC11.java @@ -40,8 +40,13 @@ import org.lwjgl.LWJGLUtil; /** + *

+ * The ALC11 class implements features in OpenAL 1.1, specifically + * ALC methods and properties. + *

* * @author Brian Matzon + * @see ALC10 * @version $Revision: 2286 $ * $Id: ALC.java 2286 2006-03-23 19:32:21 +0000 (to, 23 mar 2006) matzon $ */ @@ -81,9 +86,13 @@ public final class ALC11 { * @return ALCdevice if it was possible to open a device */ public static ALCdevice alcCaptureOpenDevice(String devicename, int frequency, int format, int buffersize) { - long device = nalcCaptureOpenDevice(devicename, frequency, format, buffersize); - if(device > 0) { - return new ALCdevice(device); + long device_address = nalcCaptureOpenDevice(devicename, frequency, format, buffersize); + if(device_address != 0) { + ALCdevice device = new ALCdevice(device_address); + synchronized (ALC10.devices) { + ALC10.devices.put(new Long(device_address), device); + } + return device; } return null; } @@ -99,7 +108,12 @@ public final class ALC11 { * @return true if device was successfully closed */ public static boolean alcCaptureCloseDevice(ALCdevice device) { - return nalcCaptureCloseDevice(ALC10.getDevice(device)); + boolean result = nalcCaptureCloseDevice(ALC10.getDevice(device)); + device.setInvalid(); + synchronized (ALC10.devices) { + ALC10.devices.remove(new Long(device.device)); + } + return result; } static native boolean nalcCaptureCloseDevice(long device); diff --git a/src/java/org/lwjgl/openal/ALCcontext.java b/src/java/org/lwjgl/openal/ALCcontext.java index 61700b19..07c76329 100644 --- a/src/java/org/lwjgl/openal/ALCcontext.java +++ b/src/java/org/lwjgl/openal/ALCcontext.java @@ -36,8 +36,14 @@ import java.nio.IntBuffer; import org.lwjgl.BufferUtils; /** - *
- * Wrapper class, to make ALC contexts behave like the orginal api. + * The ALCcontext class represents a context opened in OpenAL space. + * + * All operations of the AL core API affect a current AL context. Within the scope of AL, + * the ALC is implied - it is not visible as a handle or function parameter. Only one AL + * Context per process can be current at a time. Applications maintaining multiple AL + * Contexts, whether threaded or not, have to set the current context accordingly. + * Applications can have multiple threads that share one more or contexts. In other words, + * AL and ALC are threadsafe. * * @author Brian Matzon * @version $Revision$ @@ -45,9 +51,12 @@ import org.lwjgl.BufferUtils; */ public final class ALCcontext { - /** address of actual context */ + /** Address of actual context */ final long context; - + + /** Whether this context is valid */ + private boolean valid = false; + /** * Creates a new instance of ALCcontext * @@ -55,6 +64,7 @@ public final class ALCcontext { */ ALCcontext(long context) { this.context = context; + this.valid = true; } /* @@ -62,7 +72,7 @@ public final class ALCcontext { */ public boolean equals(Object context) { if(context instanceof ALCcontext) { - return ((ALCcontext)context).context == this.context; + return ((ALCcontext)context).context == this.context && ((ALCcontext)context).valid == this.valid; } return super.equals(context); } @@ -87,4 +97,19 @@ public final class ALCcontext { return attribList; } + + /** + * Marks this context as invalid + * + */ + void setInvalid() { + valid = false; + } + + /** + * @return true if this context is still valid + */ + public boolean isValid() { + return valid; + } } diff --git a/src/java/org/lwjgl/openal/ALCdevice.java b/src/java/org/lwjgl/openal/ALCdevice.java index d68c0ca5..9ed731bf 100644 --- a/src/java/org/lwjgl/openal/ALCdevice.java +++ b/src/java/org/lwjgl/openal/ALCdevice.java @@ -31,9 +31,18 @@ */ package org.lwjgl.openal; +import java.util.HashMap; +import java.util.Iterator; + /** - *
- * Wrapper class, to make ALC devices behave like the orginal api. + * The ALCdevice class represents a device opened in OpenAL space. + * + * ALC introduces the notion of a Device. A Device can be, depending on the + * implementation, a hardware device, or a daemon/OS service/actual server. This + * mechanism also permits different drivers (and hardware) to coexist within the same + * system, as well as allowing several applications to share system resources for audio, + * including a single hardware output device. The details are left to the implementation, + * which has to map the available backends to unique device specifiers. * * @author Brian Matzon * @version $Revision$ @@ -41,9 +50,15 @@ package org.lwjgl.openal; */ public final class ALCdevice { - /** address of actual device */ + /** Address of actual device */ final long device; + /** Whether this device is valid */ + private boolean valid = false; + + /** List of contexts belonging to the device */ + private HashMap contexts = new HashMap(); + /** * Creates a new instance of ALCdevice * @@ -51,6 +66,7 @@ public final class ALCdevice { */ ALCdevice(long device) { this.device = device; + this.valid = true; } /* @@ -58,8 +74,40 @@ public final class ALCdevice { */ public boolean equals(Object device) { if(device instanceof ALCdevice) { - return ((ALCdevice)device).device == this.device; + return ((ALCdevice)device).device == this.device && ((ALCdevice)device).valid == this.valid; } return super.equals(device); + } + + /** + * Adds a context to the device + * + * @param context context to add to the list of contexts for this device + */ + void addContext(ALCcontext context) { + synchronized (contexts) { + contexts.put(new Long(context.context), context); + } + } + + /** + * Marks this device and all of its contexts invalid + */ + void setInvalid() { + valid = false; + synchronized (contexts) { + for(Iterator i = contexts.values().iterator(); i.hasNext();) { + ALCcontext context = (ALCcontext) i.next(); + context.setInvalid(); + } + } + contexts.clear(); } + + /** + * @return true if this device is still valid + */ + public boolean isValid() { + return valid; + } } diff --git a/src/java/org/lwjgl/openal/Util.java b/src/java/org/lwjgl/openal/Util.java index c0f9794e..a3603d26 100644 --- a/src/java/org/lwjgl/openal/Util.java +++ b/src/java/org/lwjgl/openal/Util.java @@ -33,9 +33,10 @@ package org.lwjgl.openal; /** - * Simple utility class. + * Simple utility class for checking AL/ALC errors * * @author cix_foo + * @author Brian Matzon * @version $Revision$ */ @@ -44,15 +45,42 @@ public final class Util { private Util() { } - public static void checkALCError() { - int err = ALC10.alcGetError(AL.getDevice()); + /** + * Checks for any ALC errors and throws an unchecked exception on errors + * @param device Device for which to check ALC errors + */ + public static void checkALCError(ALCdevice device) { + int err = ALC10.alcGetError(device); if (err != ALC10.ALC_NO_ERROR) throw new OpenALException(ALC10.alcGetString(AL.getDevice(), err)); } + /** + * Checks for any AL errors and throws an unchecked exception on errors + */ public static void checkALError() { int err = AL10.alGetError(); if (err != AL10.AL_NO_ERROR) throw new OpenALException(err); } + + /** + * Checks for a valid device + * @param device ALCdevice to check the validity of + */ + public static void checkALCValidDevice(ALCdevice device) { + if(!device.isValid()) { + throw new OpenALException("Invalid device: " + device); + } + } + + /** + * Checks for a valid context + * @param context ALCcontext to check the validity of + */ + public static void checkALCValidContext(ALCcontext context) { + if(!context.isValid()) { + throw new OpenALException("Invalid context: " + context); + } + } }