1 /*
2  * Copyright (c) 2002-2008 LWJGL Project
3  * 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
7  * met:
8  *
9  * * Redistributions of source code must retain the above copyright
10  *   notice, this list of conditions and the following disclaimer.
11  *
12  * * Redistributions in binary form must reproduce the above copyright
13  *   notice, this list of conditions and the following disclaimer in the
14  *   documentation and/or other materials provided with the distribution.
15  *
16  * * Neither the name of 'LWJGL' nor the names of
17  *   its contributors may be used to endorse or promote products derived
18  *   from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 package org.lwjgl.openal;
33 
34 import java.nio.ByteBuffer;
35 import java.nio.IntBuffer;
36 import java.util.HashMap;
37 
38 import org.lwjgl.BufferChecks;
39 import org.lwjgl.LWJGLException;
40 import org.lwjgl.MemoryUtil;
41 
42 /**
43  *
44  * <p>
45  * ALC introduces the notion of a Device. A Device can be, depending on the
46  * implementation, a hardware device, or a daemon/OS service/actual server. This
47  * mechanism also permits different drivers (and hardware) to coexist within the same
48  * system, as well as allowing several applications to share system resources for audio,
49  * including a single hardware output device. The details are left to the
50  * implementation, which has to map the available backends to unique device
51  * specifiers (represented as strings).
52  * </p>
53  *
54  * @author Brian Matzon <brian@matzon.dk>
55  * @version $Revision: 2286 $
56  * $Id: ALC.java 2286 2006-03-23 19:32:21 +0000 (to, 23 mar 2006) matzon $
57  */
58 public final class ALC10 {
59 
60 	/** List of active contexts */
61 	static final HashMap<Long, ALCcontext> contexts = new HashMap<Long, ALCcontext>();
62 
63 	/** List of active devices */
64 	static final HashMap<Long, ALCdevice> devices = new HashMap<Long, ALCdevice>();
65 
66 	/** Bad value */
67 	public static final int ALC_INVALID = 0;
68 
69 	/** Boolean False */
70 	public static final int ALC_FALSE = 0;
71 
72 	/** Boolean True */
73 	public static final int ALC_TRUE = 1;
74 
75 	/** Errors: No Error */
76 	public static final int ALC_NO_ERROR = ALC_FALSE;
77 
78 	/** Major version query. */
79 	public static final int ALC_MAJOR_VERSION = 0x1000;
80 
81 	/** Minor version query. */
82 	public static final int ALC_MINOR_VERSION = 0x1001;
83 
84 	/**
85 	 * The size required for the zero-terminated attributes list, for the current context.
86 	 **/
87 	public static final int ALC_ATTRIBUTES_SIZE = 0x1002;
88 
89 	/**
90 	 * Expects a destination of ALC_CURRENT_ATTRIBUTES_SIZE,
91 	 * and provides the attribute list for the current context of the specified device.
92 	 */
93 	public static final int ALC_ALL_ATTRIBUTES = 0x1003;
94 
95 	/** The specifier string for the default device */
96 	public static final int ALC_DEFAULT_DEVICE_SPECIFIER = 0x1004;
97 
98 	/** The specifier string for the device */
99 	public static final int ALC_DEVICE_SPECIFIER = 0x1005;
100 
101 	/** The extensions string for diagnostics and printing */
102 	public static final int ALC_EXTENSIONS = 0x1006;
103 
104 	/** Frequency for mixing output buffer, in units of Hz. */
105 	public static final int ALC_FREQUENCY = 0x1007;
106 
107 	/** Refresh intervalls, in units of Hz. */
108 	public static final int ALC_REFRESH = 0x1008;
109 
110 	/** Flag, indicating a synchronous context. */
111 	public static final int ALC_SYNC = 0x1009;
112 
113 	/** The device argument does not name a valid device */
114 	public static final int ALC_INVALID_DEVICE = 0xA001;
115 
116 	/** The context argument does not name a valid context */
117 	public static final int ALC_INVALID_CONTEXT = 0xA002;
118 
119 	/**
120 	 * A function was called at inappropriate time, or in an inappropriate way,
121 	 * causing an illegal state. This can be an incompatible ALenum, object ID,
122 	 * and/or function.
123 	 */
124 	public static final int ALC_INVALID_ENUM = 0xA003;
125 
126 	/**
127 	 * Illegal value passed as an argument to an AL call.
128 	 * Applies to parameter values, but not to enumerations.
129 	 */
130 	public static final int ALC_INVALID_VALUE = 0xA004;
131 
132 	/**
133 	 * A function could not be completed, because there is not enough
134 	 * memory available.
135 	 */
136 	public static final int ALC_OUT_OF_MEMORY = 0xA005;
137 
initNativeStubs()138 	static native void initNativeStubs() throws LWJGLException;
139 
140 	/**
141 	 * The application can obtain certain strings from ALC.
142 	 *
143 	 * <code>ALC_DEFAULT_DEVICE_SPECIFIER</code> - The specifer string for the default device
144 	 * <code>ALC_DEVICE_SPECIFIER</code> - The specifer string for the device
145 	 * <code>ALC_EXTENSIONS</code> - The extensions string for diagnostics and printing.
146 	 *
147 	 * In addition, printable error message strings are provided for all valid error tokens,
148 	 * including <code>ALC_NO_ERROR</code>,<code>ALC_INVALID_DEVICE</code>, <code>ALC_INVALID_CONTEXT</code>,
149 	 * <code>ALC_INVALID_ENUM</code>, <code>ALC_INVALID_VALUE</code>.
150 	 *
151 	 * @param pname Property to get
152 	 * @return String property from device
153 	 */
alcGetString(ALCdevice device, int pname)154 	public static String alcGetString(ALCdevice device, int pname) {
155 		ByteBuffer buffer = nalcGetString(getDevice(device), pname);
156 		Util.checkALCError(device);
157 		return MemoryUtil.decodeUTF8(buffer);
158 	}
nalcGetString(long device, int pname)159 	static native ByteBuffer nalcGetString(long device, int pname);
160 
161 	/**
162 	 * The application can query ALC for information using an integer query function.
163 	* For some tokens, <code>null</code> is a legal deviceHandle. In other cases, specifying a <code>null</code>
164 	* device will generate an <code>ALC_INVALID_DEVICE</code> error. The application has to
165 	* specify the size of the destination buffer provided. A <code>null</code> destination or a zero
166 	* size parameter will cause ALC to ignore the query.
167 	*
168 	* <code>ALC_MAJOR_VERSION</code> - Major version query.
169 	* <code>ALC_MINOR_VERSION</code> - Minor version query.
170 	* <code>ALC_ATTRIBUTES_SIZE</code> - The size required for the zero-terminated attributes list,
171 	* for the current context. <code>null</code> is an invalid device. <code>null</code> (no current context
172 	* for the specified device) is legal.
173 	* <code>ALC_ALL_ATTRIBUTES</code> - Expects a destination of <code>ALC_CURRENT_ATTRIBUTES_SIZE</code>,
174 	* and provides the attribute list for the current context of the specified device.
175 	* <code>null</code> is an invalid device. <code>null</code> (no current context for the specified device)
176 	* will return the default attributes defined by the specified device.
177 	 *
178 	 * @param pname Property to get
179 	 * @param integerdata ByteBuffer to write integers to
180 	 */
alcGetInteger(ALCdevice device, int pname, IntBuffer integerdata)181 	public static void alcGetInteger(ALCdevice device, int pname, IntBuffer integerdata) {
182 		BufferChecks.checkDirect(integerdata);
183 		nalcGetIntegerv(getDevice(device), pname, integerdata.remaining(), MemoryUtil.getAddress(integerdata));
184 		Util.checkALCError(device);
185 	}
nalcGetIntegerv(long device, int pname, int size, long integerdata)186 	static native void nalcGetIntegerv(long device, int pname, int size, long integerdata);
187 
188 	/**
189 	 * The <code>alcOpenDevice</code> function allows the application (i.e. the client program) to
190 	* connect to a device (i.e. the server).
191 	*
192 	* If the function returns <code>null</code>, then no sound driver/device has been found. The
193 	* argument is a null terminated string that requests a certain device or device
194 	* configuration. If <code>null</code> is specified, the implementation will provide an
195 	* implementation specific default.
196 	 *
197 	 * @param devicename name of device to open
198 	 * @return opened device, or null
199 	 */
alcOpenDevice(String devicename)200 	public static ALCdevice alcOpenDevice(String devicename) {
201 		ByteBuffer buffer = MemoryUtil.encodeUTF8(devicename);
202 		long device_address = nalcOpenDevice(MemoryUtil.getAddressSafe(buffer));
203 		if(device_address != 0) {
204 			ALCdevice device = new ALCdevice(device_address);
205 			synchronized (ALC10.devices) {
206 				devices.put(device_address, device);
207 			}
208 			return device;
209 		}
210 		return null;
211 	}
nalcOpenDevice(long devicename)212 	static native long nalcOpenDevice(long devicename);
213 
214 	/**
215 	 * The <code>alcCloseDevice</code> function allows the application (i.e. the client program) to
216 	* disconnect from a device (i.e. the server).
217 	*
218 	* If deviceHandle is <code>null</code> or invalid, an <code>ALC_INVALID_DEVICE</code> error will be
219 	* generated. Once closed, a deviceHandle is invalid.
220 	 *
221 	 * @param device address of native device to close
222 	 */
alcCloseDevice(ALCdevice device)223 	public static boolean alcCloseDevice(ALCdevice device) {
224 		boolean result = nalcCloseDevice(getDevice(device));
225 		synchronized (devices) {
226 			device.setInvalid();
227 			devices.remove(new Long(device.device));
228 		}
229 		return result;
230 
231 	}
nalcCloseDevice(long device)232 	static native boolean nalcCloseDevice(long device);
233 
234 	/**
235 	 * A context is created using <code>alcCreateContext</code>. The device parameter has to be a valid
236 	* device. The attribute list can be <code>null</code>, or a zero terminated list of integer pairs
237 	* composed of valid ALC attribute tokens and requested values.
238 	*
239 	* Context creation will fail if the application requests attributes that, by themselves,
240 	* can not be provided. Context creation will fail if the combination of specified
241 	* attributes can not be provided. Context creation will fail if a specified attribute, or
242 	* the combination of attributes, does not match the default values for unspecified
243 	* attributes.
244 	 *
245 	 * @param device address of device to associate context to
246 	 * @param attrList Buffer to read attributes from
247 	 * @return New context, or null if creation failed
248 	 */
alcCreateContext(ALCdevice device, IntBuffer attrList)249 	public static ALCcontext alcCreateContext(ALCdevice device, IntBuffer attrList) {
250 		long context_address = nalcCreateContext(getDevice(device), MemoryUtil.getAddressSafe(attrList));
251 		Util.checkALCError(device);
252 
253 		if(context_address != 0) {
254 			ALCcontext context = new ALCcontext(context_address);
255 			synchronized (ALC10.contexts) {
256 				contexts.put(context_address, context);
257 				device.addContext(context);
258 			}
259 			return context;
260 		}
261 		return null;
262 	}
nalcCreateContext(long device, long attrList)263 	static native long nalcCreateContext(long device, long attrList);
264 
265 	/**
266 	 * To make a Context current with respect to AL Operation (state changes by issueing
267 	* commands), <code>alcMakeContextCurrent</code> is used. The context parameter can be <code>null</code>
268 	* or a valid context pointer. The operation will apply to the device that the context
269 	* was created for.
270 	*
271 	* For each OS process (usually this means for each application), only one context can
272 	* be current at any given time. All AL commands apply to the current context.
273 	* Commands that affect objects shared among contexts (e.g. buffers) have side effects
274 	* on other contexts.
275 	 *
276 	 * @param context address of context to make current
277 	 * @return true if successfull, false if not
278 	 */
alcMakeContextCurrent(ALCcontext context)279 	public static int alcMakeContextCurrent(ALCcontext context) {
280 		return nalcMakeContextCurrent(getContext(context));
281 	}
nalcMakeContextCurrent(long context)282 	static native int nalcMakeContextCurrent(long context);
283 
284 	/**
285 	 * The current context is the only context accessible to state changes by AL commands
286 	 * (aside from state changes affecting shared objects). However, multiple contexts can
287 	 * be processed at the same time. To indicate that a context should be processed (i.e.
288 	 * that internal execution state like offset increments are supposed to be performed),
289 	 * the application has to use <code>alcProcessContext</code>.
290 	 *
291 	 * Repeated calls to <code>alcProcessContext</code> are legal, and do not affect a context that is
292 	 * already marked as processing. The default state of a context created by
293 	 * alcCreateContext is that it is not marked as processing.
294 	 */
alcProcessContext(ALCcontext context)295 	public static void alcProcessContext(ALCcontext context) {
296 		nalcProcessContext(getContext(context));
297 	}
nalcProcessContext(long context)298 	static native void nalcProcessContext(long context);
299 
300 	/**
301 	 * The application can query for, and obtain an handle to, the current context for the
302 	* application. If there is no current context, <code>null</code> is returned.
303 	 *
304 	 * @return Current ALCcontext
305 	 */
alcGetCurrentContext()306 	public static ALCcontext alcGetCurrentContext() {
307 		ALCcontext context = null;
308 		long context_address = nalcGetCurrentContext();
309 		if(context_address != 0) {
310 			synchronized (ALC10.contexts) {
311 				context = ALC10.contexts.get(context_address);
312 			}
313 		}
314 		return context;
315 	}
nalcGetCurrentContext()316 	static native long nalcGetCurrentContext();
317 
318 	/**
319 	 * The application can query for, and obtain an handle to, the device of a given context.
320 	 *
321 	 * @param context address of context to get device for
322 	 */
alcGetContextsDevice(ALCcontext context)323 	public static ALCdevice alcGetContextsDevice(ALCcontext context) {
324 		ALCdevice device = null;
325 		long device_address = nalcGetContextsDevice(getContext(context));
326 		if (device_address != 0) {
327 			synchronized (ALC10.devices) {
328 				device = ALC10.devices.get(device_address);
329 			}
330 		}
331 		return device;
332 	}
nalcGetContextsDevice(long context)333 	static native long nalcGetContextsDevice(long context);
334 
335 	/**
336 	 * The application can suspend any context from processing (including the current
337 	 * one). To indicate that a context should be suspended from processing (i.e. that
338 	 * internal execution state like offset increments is not supposed to be changed), the
339 	 * application has to use <code>alcSuspendContext</code>.
340 	 *
341 	 * Repeated calls to <code>alcSuspendContext</code> are legal, and do not affect a context that is
342 	 * already marked as suspended. The default state of a context created by
343 	 * <code>alcCreateContext</code> is that it is marked as suspended.
344 	 *
345 	 * @param context address of context to suspend
346 	 */
alcSuspendContext(ALCcontext context)347 	public static void alcSuspendContext(ALCcontext context) {
348 		nalcSuspendContext(getContext(context));
349 	}
nalcSuspendContext(long context)350 	static native void nalcSuspendContext(long context);
351 
352 	/**
353 	 * The correct way to destroy a context is to first release it using <code>alcMakeCurrent</code> and
354 	* <code>null</code>. Applications should not attempt to destroy a current context.
355 	 *
356 	 * @param context address of context to Destroy
357 	 */
alcDestroyContext(ALCcontext context)358 	public static void alcDestroyContext(ALCcontext context) {
359 		synchronized(ALC10.contexts) {
360 			ALCdevice device = alcGetContextsDevice(context);
361 			nalcDestroyContext(getContext(context));
362 			device.removeContext(context);
363 			context.setInvalid();
364 		}
365 	}
nalcDestroyContext(long context)366 	static native void nalcDestroyContext(long context);
367 
368 	/**
369 	 * ALC uses the same conventions and mechanisms as AL for error handling. In
370 	* particular, ALC does not use conventions derived from X11 (GLX) or Windows
371 	* (WGL). The <code>alcGetError</code> function can be used to query ALC errors.
372 	*
373 	* Error conditions are specific to the device.
374 	*
375 	* ALC_NO_ERROR - The device handle or specifier does name an accessible driver/server.
376 	* <code>ALC_INVALID_DEVICE</code> - The Context argument does not name a valid context.
377 	* <code>ALC_INVALID_CONTEXT</code> - The Context argument does not name a valid context.
378 	* <code>ALC_INVALID_ENUM</code> - A token used is not valid, or not applicable.
379 	* <code>ALC_INVALID_VALUE</code> - An value (e.g. attribute) is not valid, or not applicable.
380 	 *
381 	 * @return Errorcode from ALC statemachine
382 	 */
alcGetError(ALCdevice device)383 	public static int alcGetError(ALCdevice device) {
384 		return nalcGetError(getDevice(device));
385 	}
nalcGetError(long device)386 	static native int nalcGetError(long device);
387 
388 	/**
389 	* Verify that a given extension is available for the current context and the device it
390 	* is associated with.
391 	* A <code>null</code> name argument returns <code>ALC_FALSE</code>, as do invalid and unsupported string
392 	* tokens.
393 	 *
394 	 * @param extName name of extension to find
395 	 * @return true if extension is available, false if not
396 	 */
alcIsExtensionPresent(ALCdevice device, String extName)397 	public static boolean alcIsExtensionPresent(ALCdevice device, String extName) {
398 		ByteBuffer buffer = MemoryUtil.encodeASCII(extName);
399 		boolean result = nalcIsExtensionPresent(getDevice(device), MemoryUtil.getAddress(buffer));
400 		Util.checkALCError(device);
401 		return result;
402 	}
nalcIsExtensionPresent(long device, long extName)403 	private static native boolean nalcIsExtensionPresent(long device, long extName);
404 
405 	/**
406 	 * Enumeration/token values are device independend, but tokens defined for
407 	* extensions might not be present for a given device. But only the tokens defined
408 	* by the AL core are guaranteed. Availability of extension tokens dependends on the ALC extension.
409 	*
410 	* Specifying a <code>null</code> name parameter will cause an <code>ALC_INVALID_VALUE</code> error.
411 	 *
412 	 * @param enumName name of enum to find
413 	 * @return value of enumeration
414 	 */
alcGetEnumValue(ALCdevice device, String enumName)415 	public static int alcGetEnumValue(ALCdevice device, String enumName) {
416 		ByteBuffer buffer = MemoryUtil.encodeASCII(enumName);
417 		int result = nalcGetEnumValue(getDevice(device), MemoryUtil.getAddress(buffer));
418 		Util.checkALCError(device);
419 		return result;
420 	}
nalcGetEnumValue(long device, long enumName)421 	private static native int nalcGetEnumValue(long device, long enumName);
422 
getDevice(ALCdevice device)423 	static long getDevice(ALCdevice device) {
424 		if(device != null) {
425 			Util.checkALCValidDevice(device);
426 			return device.device;
427 		}
428 		return 0L;
429 	}
430 
getContext(ALCcontext context)431 	static long getContext(ALCcontext context) {
432 		if(context != null) {
433 			Util.checkALCValidContext(context);
434 			return context.context;
435 		}
436 		return 0L;
437 	}
438 
439 }
440