GWT-AL - OpenAL implementation for the GWT platform

An OpenAL implementation based on WebAudio API for GWT. Currently supports loading buffers and playing sources as well as setting properties like position, velocity, gain, pitch etc., allowing to easily port OpenAL applications to the Web platform using GWT.
[h1]Design[/h1]
The design is to conform to the OpenAL 1.1 Specification and the API is to be compatible with the OpenAL bindings API of the LWJGL project. The implementation is based on the WebAudio API bindings written internal to this library (but are also exposed). The developer is free to use either OpenAL or WebAudio API with this library.
[h1]Installation[/h1]
The only way to install for now is to clone the repo and build it manually. I will release the JAR and in maven central once the library is out of alpha and all the remaining OpenAL API has been implemented.


./gradlew clean build javadoc

That should create a JAR file called as gwt-al.jar which you should add to the classpath of your GWT project. Now inherit the GWT-AL library in your module.


<inherits name='com.shc.gwtal.client'/>

That should make you able to use the OpenAL API as well as the WebAudio API bindings in the module which inherits GWT-AL. You can now proceed to write your audio application.
[h1]Context Creation[/h1]
The initial step is to create a context that can be used as a handle to the audio. Note that this throws a [icode]AudioContextException[/icode] which is a checked exception and must be caught by the developer when creating the context.


try
{
    AudioContext context = AudioContext.create();
}
catch (AudioContextException e)
{
    e.printStackTrace();
}

The OpenAL context creation is different, and you need to make the context current, so as to conform to the API. It will throw the [icode]AudioContextException[/icode] too.


try
{
    ALContext context = ALContext.create();
    AL.setCurrentContext(context);
}
catch (AudioContextException e)
{
    e.printStackTrace();
}

Why this occurs is that whenever you create an [icode]ALContext[/icode] instance, an [icode]AudioContext[/icode] object is created too, because the OpenAL implementation uses the underlying AudioContext to play the actual audio. If that creation is failed, then the exception is thrown, so OpenAL is also not possible on browsers that don’t support WebAudio API.
[h1]Links[/h1]
The project is still in the alpha and doesn’t even contain the complete implementation. However it does support everything that a normal user needs (except that it’s missing features like doppler shift and streaming sources).


GitHub Repository | Online Examples | Examples (Source)

If you would like to be a tester, and have an intermediate knowledge in OpenAL, please contact me. If you had any issues, please report them to me either in this thread, or through PMs, or even on GitHub issues.

GWT-AL snapshots are now available through OSSRH repositories.

[icode]Maven[/icode]


<dependency>
    <groupId>com.goharsha</groupId>
    <artifactId>gwt-al</artifactId>
    <version>0.1-SNAPSHOT</version>
</dependency>

[icode]Gradle[/icode]


compile 'com.goharsha:gwt-al:0.1-SNAPSHOT'

Make sure that you have maven repository https://oss.sonatype.org/content/repositories/snapshots/ present in your search path and this will work. The builds will be uploaded for every commit on the master branch.

GWT-AL is now version 0.2-SNAPSHOT. The main change is that the older version will not work anymore due to the recent deprecations to some nodes in the Web Audio API and Chrome is issuing warnings in the console.

The new version have fixed that issue, and also implemented doppler shift on the sources. Additionally a number of old bugs are fixed. In case you are using the older version, change it immediately and if you have any code already compiled, you’d have to recompile it. There is no change in the public API.

[icode]Maven[/icode]


<dependency>
    <groupId>com.goharsha</groupId>
    <artifactId>gwt-al</artifactId>
    <version>0.2-SNAPSHOT</version>
</dependency>

[icode]Gradle[/icode]


compile 'com.goharsha:gwt-al:0.2-SNAPSHOT'

All the users are requested to update to the new version as soon as possible.

Hi SHC,

Just playing around with your library. The Web Audio API example works perfectly, however, the Open AL example only comes through the right speaker.

Any ideas? I’m using Chrome on Windows 10.

Thanks.

EDIT: Looks like it’s only Chrome that the sound comes out only through the right speaker. Firefox works with both speakers, while IE and Edge don’t work at all. You can see it happening in http://drift.team/, just click on the “Sounds” button. Do you know if these browsers should be working with GWT-AL?

I have seen your post, but sorry for the late reply, it is festival time here, and my semester examinations are also approaching at the same time. I did saw the same issue, and it really seems like a bug in the WebAudio API implementations of Chrome and Firefox. I find that there are small differences between the versions of the specifications used by these two browsers.

Right now, it appears that Chrome implementing the latest draft specification, which Firefox is with an older spec, and that both browsers has the same amount of bugs in some areas. IMO Edge has a better implementation than these major browsers, but unfortunately Edge does not support OGG file format.

My latest commit url=https://github.com/sriharshachilakapati/GWT-AL/commit/e6d9eb9c0fd7246da3634d7da2950c871b127760[/url] tries to fix the issue on Chrome by disconnecting the sound’s panner nodes once the playback is done, and this seems to have some effect at least. As a test, you can try my Lost-Orion game and check it’s audio. It fixes the issue in Chrome as per my ears, but there are still issues in FF.

The major issue I find in Firefox is with sound sources that move while the source is still playing. When this happens, Chrome handles this perfectly smooth, but in FF I’m seeing some small pauses while the position of the node is being changed. I’m still looking for a solution to this.

Thanks SHC. It appears your Lost-Orion game has the same problem as I am having (sound only comes out of the right speaker in Chrome).

I’ll look into doing direct JS calls to the Web Audio API, to see if I can work out what is going on.

Cheers.

Update: I created a bare bones AudioContext, I didn’t do anything fancy like in your AudioContext.java when you decodeAudioData, you do some sort of slicing, instead I just passed the ArrayBuffer straight into the decodeAudioData. Basically, I implemented https://www.html5rocks.com/en/tutorials/webaudio/intro/ in GWT.

I also called createStereoPanner, and I could move my sounds between the speakers.

However, when I called createOscillator, the sound from that only came out the right speaker, and completely ignored my connected Stereo Panner.

@Ranger

There is a reason why I do slicing the buffer audio data. It is because Firefox doesn’t copy the data into the buffer, but it uses the same buffer. It does also modify the contents. For example, I got a buffer, and if I create two source nodes with that buffer, then it will not play the second node. Only the first node can be heard.

Did you test it with both Chrome and Firefox? Last time I tried, Chrome throw’ed me an error when I created SterioPannerNode. All the code in GWT-AL is using PannerNode instead of SterioPannerNode.

GWT-AL does not use the OscillatorNode, so am not actually sure where the bug is coming from. Maybe I have to check again and replace PannerNode with SterioPannerNode. Will check this and reply back soon.

Firefox seems to work fine. Although the looping of a sound is a little glitchy. There is no problem with playing multiple sounds at the same time. I just deployed a new version, so you can hear it running with direct calls to AudioContext, and coming through both speakers http://drift.team/.

I think Chrome has a bug in it with the OscillatorNode, as other people’s examples also only come through the right speaker. Eg: http://www.javascripture.com/OscillatorNode Edit: I was wrong, Chrome works fine.

Also, AudioContext seems to work fine on Android, but I haven’t been able to get it to work on an iPhone.

Cheers.

I’ve been trying to get sounds working in Chrome on the iPhone. First it was failing with the XMLHttpRequest, so I wrote a method that converted the DataResource to a ArrayBuffer without using XMLHttpRequest (as the DataResource was already loaded by GWT):


/**
 * Convert a base64 URL into an array buffer.  Ref: http://stackoverflow.com/questions/21797299
 */
private static native ArrayBuffer arrayBufferFromBase64Url(String base64Url) /*-{
	var base64Value = base64Url.split(',')[1];
	var binaryStr = $wnd.atob(base64Value);
	var len = binaryStr.length;
	var bytes = new Uint8Array(len);

	for (var i=0; i<len; i++) {
		bytes[i] = binaryStr.charCodeAt(i);
	}

	return bytes.buffer;
}-*/;

/**
 * Create the sound Array Buffer from the data resource.
 */
public static ArrayBuffer createSoundArrayBuffer(DataResource soundData) {
	String url = soundData.getSafeUri().asString();

	return arrayBufferFromBase64Url(url);
}

However, now it hangs on the decodeAudioData call. It doesn’t seem to call the success or failed function:


public class AudioContext extends JavaScriptObject {
	public native final void decodeAudioData(ArrayBuffer audioData, Loaded<AudioBuffer> success, Loaded<String> failed) /*-{
		this.decodeAudioData(
			audioData,
			function (decodedData) {
				success.@team.drift.client.common.model.Loaded::data(*)(decodedData);
			},
			function (e) {
				failed.@team.drift.client.common.model.Loaded::data(*)(e.err);
			}
		);
	}-*/;
}

It works fine in Chrome on PC, Mac, and Android. Just the iPhone is failing. Any ideas would be great!

EDIT: Finally got it working on iPhone. Turns out, iPhone does not support OGG files. >:( Switching to MP3 made the sounds work.

@Ranger

Sorry for being so late to reply, was having my end semester exams, and I have to study hard to keep my grades. Anyways, I don’t think you are using panner at all, you seem to not needing the 3D sound right? My observation is that this issue appears only when we needed panning and had a panner node created.

This might be with the panning models, I will revisit the specification soon and will try to find out the problem.

No problem at all. Good luck with your exams!

Yes, you are correct, I don’t need a panner or any 3D sound.

I’m finding out that there is a lot of stuff happening in the background. Eg: GWT converts DataResources into inline data URLs if the sound byte is small enough (around 50K), so, when you call getSafeUri(), you will either get a base64 data url, or an http url, depending on the size. Then, the XMLHttpRequest request will fail on the iPhone if it is a base64 data url, however, if it is a http url, then you need the XMLHttpRequest call.

So, the code I posted above will only work on small sound bytes that have been converted to base64 data urls.

Right now, I have all my sound effects small enough so they all get converted into base64 urls, and have written my own hooks into JS to play them, setting their volume, pitch, etc. And for the music, I’m using GWTs default Audio.createIfSupported(). I noticed there was a bug in that code when listening for the end of a music track, so I wrote a new JS method:


private static native final void listenForEnd(AudioElement aud, Command onComplete) /*-{
	aud.onended = function() {
		onComplete.@com.google.gwt.user.client.Command::execute(*)();
	};
}-*/;

Anyway, I seem to have everything now working on all supported platforms. Let me know if you have any problems with your framework, maybe I can help out.

Cheers.