AL Contexts and the ALC API This section of the AL specification describes ALC, the AL Context API. ALC is a portable API for managing &AL; contexts, including resource sharing, locking, and unlocking. Within the core AL API the existence of a Context is implied, but the Context is not exposed. The Context encapsulates the state of a given intance of the AL state machine. To avoid confusion with the AL related prefixes implied throughout this document, the "alc" and "ALC_" prefixes have been made explicit in the ALC related sections. ALC defines the following objects: Contexts. Annotation (ALC entry points) While the actual ALC implemention might be supplied as a separate library, or as part of a server or daemon, the specification requires that the AL library provides the actual ALC entry points. ]]> Annotation (ALC OS independend) ALC is meant to be OS-independent. OS specifics are expected to be adressed by defining proper device specifiers strings, and configuration attributes. In this, ALC differs from GLX/WGL, which (due to the tighter coupling with the window manager and operating system) attempt to abstract OS specifics to a much lesser degree. ]]> RFC/ Issues Hardware init/deinit, mapping many processes with multiple contexts to many devices, sharing resources among processes. ]]> Managing Devices 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 uniq7ue device specifiers (represented as strings). Annotation (Network transparency) &AL; is meant for interoperability with &OGL;. Some implementations of &OGL; bindings (e.g. GLX) are network transparent. The Device API theoretically allows for a network transparent AL implementation. No wire protocol is specified, no specification or implementation is planned. ]]> Annotation (Device Enumeration) At this time, ALC does not provide mechanism to query for available devices, and request device enumerations. This might be added at a later time, depending on demand and the ability to abstract OS and configuration specifics. ]]> Annotation (X11 Audio) The ALC API intentionally mimicks XOpenDisplay and XCloseDisplay. There is no X Audio standard, although proposals have been made in the past. The ALC API design accounts for this possibility in a minimal way. ]]> Connecting to a Device The alcOpenDevice function allows the application (i.e. the client program) to connect to a device (i.e. the server). &device; * alcOpenDevice const &ubyte;* deviceSpecifier If the function returns NULL, then no sound driver/device has been found. The argument is a null terminated string that requests a certain device or device configuration. If NULL is specified, the implementation will provide an implementation specific default. Annotation (Operating system dependencies) At this point, system specific configuration, and operating system specific details, are handled by leaving the details of the string specifier to the implementation. The application coder has to determine how he wants to obtain this information from the OS or the user. If, at a later point, device enumeration and configuration requests are supported through ALC, the resulting string might still be operating system and implementation specific. ]]> Disconnecting from a Device The alcCloseDevice function allows the application (i.e. the client program) to disconnect from a device (i.e. the server). &void; alcCloseDevice &device; * deviceHandle If deviceHandle is NULL or invalid, an ALC_INVALID_DEVICE error will be generated. Once closed, a deviceHandle is invalid. Managing Rendering Contexts 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 INprocess 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. The default AL Context interoperates with a hardware device driver. The application manages hardware and driver resources by communicating through the ALC API, and configures and uses such Contexts by issuing AL API calls. A default AL Context processes AL calls and sound data to generate sound output. Such a Context is called a Rendering Context. There might be non-rendering contexts in the future. The word "rendering" was chosen intentionally to emphasize the primary objective of the AL API - spatialized sound - and the underlying concept of AL as a sound synthesis pipeline that simulates sound propagation by specifying spatial arrangements of listeners, filters, and sources. If used in describing an application that uses both &OGL; and &AL;, "sound rendering context" and "graphics rendering context" should be used for clarity. Throughout this document, "rendering" is used to describe spatialized audio synthesis (avoiding ambiguous words like "processing", as well as proprietary and restrictive terms like "wavetracing"). Context Attributes The application can choose to specify certain attributes for a context. Attributes not specified explicitely are set to implementation dependend defaults. Context Attributes Name Description ALC_FREQUENCY Frequency for mixing output buffer, in units of Hz. ALC_REFRESH Refresh intervalls, in units of Hz. ALC_SYNC Flag, indicating a synchronous context.
Annotation (Refresh Control) Applications might have a fixed, or bounded, schedule for state changes (e.g. synchronously with the GL framerate). In this case it is desirable to specify the mixahead interval (milliseconds), or refresh rate (Hz), for the mixing thread. This is especially important for a synchronous context, where the application has to specify the refresh interval it intends to keep. ]]> RFC / Mixing Buffer Configuration ALC_RESOLUTION was originally used to specify the accuracy of the mixing output buffer. For the time being this is not supported, but could be added if mixing path and result accuracy control is desirable to scale resource requirements. A full ALC_FORMAT (including channel and other attributes) does not make sense for rendering contexts, but will be necessary for PBuffers (mix to memory). ]]> RFC / LOKI extensions ALC_SOURCES_HINT_LOKI, /* # of sources to pre-allocate */ ALC_BUFFERS_HINT_LOKI, /* # of buffers to pre-allocate */ ALC_CD_LOKI, /* demand CD/DVD control */ ]]>
Creating a Context A context is created using alcCreateContext. The device parameter has to be a valid device. The attribute list can be NULL, or a zero terminated list of integer pairs composed of valid ALC attribute tokens and requested values. &context; * alcCreateContext const &device; * deviceHandle ∫ * attrList Context creation will fail if the application requests attributes that, by themselves, can not be provided. Context creation will fail if the combination of specified attributes can not be provided. Context creation will fail if a specified attribute, or the combination of attributes, does not match the default values for unspecified attributes. Selecting a Context for Operation To make a Context current with respect to AL Operation (state changes by issueing commands), alcMakeContextCurrent is used. The context parameter can be NULL or a valid context pointer. The operation will apply to the device that the context was created for. &bool; alcMakeContextCurrent &context; * context For each OS process (usually this means for each application), only one context can be current at any given time. All AL commands apply to the current context. Commands that affect objects shared among contexts (e.g. buffers) have side effects on other contexts. Annotation (No Explicit Device) An ALC context is bound to the device it was created for. The context carries this information, thus removing the need to specify the device explicitely. Contexts can not be made current for any other device aside from the one they were created for. ]]> Annotation (No Multiple Current) There is only one current context per process, even in multithreaded applications, even if multiple devices are used. ]]> Annotation (Current NULL) The implementation is encouraged to exploit optimizations possible if the application sets the current context to NULL, indicating that no state changes are intended for the time being. The application should not set the current context to NULL if more state changes are pending on the most recent, or another context created for the same device. ]]> Annotation (Shared Objects) Buffers are shared among contexts. As mutiple contexts can exist at the same time, the state of shared objects is also shared among contexts. ]]> RFC / Buffer Deletion Buffers that have not yet been processed in another context can not be deleted from any other context. ]]> Initiate Context Processing The current context is the only context accessible to state changes by AL commands (aside from state changes affecting shared objects). However, multiple contexts can be processed at the same time. To indicate that a context should be processed (i.e. that internal execution state like offset increments are supposed to be performed), the application has to use alcProcessContext. &void; alcProcessContext &context; * context Repeated calls to alcProcessContext are legal, and do not affect a context that is already marked as processing. The default state of a context created by alcCreateContext is that it is not marked as processing. Annotation (Sync and async implementations) Unfortunately, the exact semantics of alcProcessContext is not independend of the implementation. Ideally it should be completely transparent to the application whether the sound driver is threaded or synced. Unfortunately a synced context has to have its execution initiated by the application, which requires calls of alcProcessContext timed in accordance to the drivers mixahead, or the rendering buffer will underflow. For a threaded driver, the implementation is free to consider alcProcessContext a NOP once the context has been marked as processing. One consequence is that an application that was developed using a threaded implementation of AL might not work properly with a synchronous implementation of AL (on the other hand, an AL application that works using a synchronous implementation is guaranteed to work with a threaded implementation. Enforcing alcProcessContext calls would defeat the purpose of a threaded implementation. Permitting the AL implementation to e.g. schedule optimizations based on alcProcessContext calls would similarly obfuscate the exact semantincs. Consequently, the application coder has to accept this implementation dependency, and has to rely on the ALC_SYNC attribute to explicitely request a synchronous implementation. The implementation can expect the application to be aware of the additonal constraints imposed on alcProcessContext in this case. ]]> Annotation (Multiple Contexts and SYNC refresh) The application can request SYNC contexts or threaded contexts, however, the implementation is not obliged to provide both, or provide a mixture of both on the same device. ]]> RFC/ Implications for Networking What does alcProcessContext imply for networking? For AL, will we add alFlush/alFinish? ]]> Suspend Context Processing The application can suspend any context from processing (including the current one). To indicate that a context should be suspended from processing (i.e. that internal execution state like offset increments is not supposed to be changed), the application has to use alcSuspendContext. &void; alcSuspendContext &context; * context Repeated calls to alcSuspendContext are legal, and do not affect a context that is already marked as suspended. The default state of a context created by alcCreateContext is that it is marked as suspended. Annotation (Sync and async implementations) Unfortunately, the exact semantics of alcSuspendContext is also not independend of the implementation. For a threaded implementation, alcSuspendContext is necessary to ensure a context is not processed. For a synchronous implementation, omitting alcProcessContext calls will ultimately have the same effect, but will also generate rendering buffer underflow errors. Again, the application coder that requests a synchronous context using ALC_SYNC has to make sure that alcSuspendContext is used accordingly. ]]> Annotation (Suspending vs. Muting a context) By setting Listener GAIN to zero, an application can mute a context, and expect the implementation to bypass all rendering. However, the context is still processing, and the internal execution state is still updated accordingly. Suspending a context, whether muted or not, will incidentally suspend rendering as well. However, it is the application's responsibility to prevent artifacts (e.g. by proper GAIN control to fade in and out). It is recommended to mute a context before suspending. ]]> Annotation (Current Context Suspended) It is possible to make a suspended context current, or suspend the current context. In this case, the implementation is still obliged to immediately verify AL commands as they are issued, and generate errors accordingly. The implementation is permitted to postpone propagating the actual state changes until the context is marked for processing again, with the exception of dereferencing data (e.g. buffer contents). For efficiency reasons (memory usage), most if not all AL commands applied to a suspended context will usually be applied immediately. State changes will have to be applied in the sequence they were requested. It is possible to use suspension of a current context as an explicit locking (to enforce apparent synchronicity), but execution is still guaranteed to be in sequence, and the implementation is not expected to optimize this operation. A typical use would be setting up the initial configuration while loading a scene. ]]> Annotation (Release of Hardware Resources) The specification does not guarantee that the implementation will release hardware resources used by a suspended context. This might well depend on the details of the hardware and driver. Neither a muted context nor a suspended context can be expected to free device resources. If all contexts for a given device are suspended, and no context of this device is current, the implementation is expected to release all hardware resources if possible. ]]> Destroying a Context &void; alcDestroyContext &context; * context The correct way to destroy a context is to first release it using alcMakeCurrent and NULL. Applications should not attempt to destroy a current context.
ALC Queries Query for Current Context The application can query for, and obtain an handle to, the current context for the application. If there is no current context, NULL is returned. &context; * alcGetCurrentContext Query for a Context's Device The application can query for, and obtain an handle to, the device of a given context. &device; * alcGetContextsDevice &context; * context Query For Extensions To verify that a given extension is available for the current context and the device it is associated with, use &bool;IsExtensionPresent const &device; * deviceHandle const &ubyte; * extName A NULL name argument returns FALSE, as do invalid and unsupported string tokens. A NULL deviceHandle will result in an INVALID_DEVICE error. Annotation (Exlicit Device Parameter) Certain ALC Extensions might be relevant to context creation (like additional attributes, or support for unusual multi-context combinations), thus the application might have to query these before a context is created. On the other hand, ALC Extensions are specific to the device. ]]> Query for Function Entry Addresses The application is expected to verify the applicability of an extension or core function entry point before requesting it by name, by use of alcIsExtensionPresent. &void; * alcGetProcAddress const &device; * deviceHandle const &ubyte; * funcName Entry points can be device specific, but are not context specific. Using a NULL device handle does not guarantee that the entry point is returned, even if available for one of the available devices. Specifying a NULL name parameter will cause an ALC_INVALID_VALUE error. Retrieving Enumeration Values Enumeration/token values are device independend, but tokens defined for extensions might not be present for a given device. Using a NULL handle is legal, but only the tokens defined by the AL core are guaranteed. Availability of extension tokens dependends on the ALC extension. &uint; alcGetEnumValue const &device; * deviceHandle const &ubyte; enumName Specifying a NULL name parameter will cause an ALC_INVALID_VALUE error. Query for Error Conditions ALC uses the same conventions and mechanisms as AL for error handling. In particular, ALC does not use conventions derived from X11 (GLX) or Windows (WGL). The alcGetError function can be used to query ALC errors. &enum;alcGetError &device; * deviceHandle Error conditions are specific to the device. Error Conditions Name Description ALC_NO_ERROR The device handle or specifier does name an accessible driver/server. ALC_INVALID_DEVICE The Context argument does not name a valid context. ALC_INVALID_CONTEXT The Context argument does not name a valid context. ALC_INVALID_ENUM A token used is not valid, or not applicable. ALC_INVALID_VALUE An value (e.g. attribute) is not valid, or not applicable.
Annotation (No UNDERFLOW error) Applications using synchronous (and, depending on CPU load, even an asynchronous implementation itself) might fail to prevent underflow of the rendering output buffer. No ALC error is generated in these cases, as it this error condition can not be applied to a specific command. ]]>
String Query The application can obtain certain strings from ALC. const &ubyte; * alcGetString &device; * deviceHandle &enum; token For some tokens, NULL is is a legal value for the deviceHandle. In other cases, specifying a NULL device will generate an ALC_INVALID_DEVICE error. String Query Tokens Name Description ALC_DEFAULT_DEVICE_SPECIFIER The specifier string for the default device (NULL handle is legal). ALC_DEVICE_SPECIFIER The specifier string for the device (NULL handle is not legal). ALC_EXTENSIONS The extensions string for diagnostics and printing.
In addition, printable error message strings are provided for all valid error tokens, including ALC_NO_ERROR, ALC_INVALID_DEVICE, ALC_INVALID_CONTEXT, ALC_INVALID_ENUM, ALC_INVALID_VALUE.
Integer Query The application can query ALC for information using an integer query function. &void; alcGetIntegerv &device; * deviceHandle &enum; token &sizei; size dest For some tokens, NULL is a legal deviceHandle. In other cases, specifying a NULL device will generate an ALC_INVALID_DEVICE error. The application has to specify the size of the destination buffer provided. A NULL destination or a zero size parameter will cause ALC to ignore the query. Integer Query Tokens Name Description ALC_MAJOR_VERSION Major version query. ALC_MINOR_VERSION Minor version query. ALC_ATTRIBUTES_SIZE The size required for the zero-terminated attributes list, for the current context. NULL is an invalid device. NULL (no current context for the specified device) is legal. ALC_ALL_ATTRIBUTES Expects a destination of ALC_CURRENT_ATTRIBUTES_SIZE, and provides the attribute list for the current context of the specified device. NULL is an invalid device. NULL (no current context for the specified device) will return the default attributes defined by the specified device.
Annotation (Backward Compatibility) Backward compatibility is guaranteed only for minor revisions. Breaking ABI backwards compatibility will require a issuing major revision. ]]> RFC / Version Matching The ALC version can be different from the AL version. The ALC major version has to be identical between application and driver (client and server). The ALC minor version can differ between client and server, and the minimum of the two minor version numbers is returned. ]]> RFC / Device Enumeration ALC_NUM_DEVICE_SPECIFIERS could be provided as an extension, but it requires the number of device configurations to be finite and small, as they are to be represented by strings. ]]>
Shared Objects For efficiency reasons, certain AL objects are shared across ALC contexts. At this time, AL buffers are the only shared objects. RFC/ Sharing Sources? Mike Kelly from Dynamix describes an application scenario with multiple camera views of the same scene (implemented using several viewports on a single, "split screen", context) in which he needs multiple listeners (one per view) to preceive the same sources, with the rendering results of each listener to mixed for a single output device. As an alternative to permitting multiple listeners within a context, it might be preferable to introduce a mechanism to explicitely share certain AL objects among contexts, at a later time. It is not desirable to share Sources by default, especially as the more common multi-listener application is expected to maintain listeners with disjunct sets of sources. ]]> Shared Buffers Buffers are shared among contexts. The processing state of a buffer is determined by the dependencies imposed by all contexts, not just the current context. This includes suspended contexts as well as contexts that are processing.