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);
+ }
+ }
}