-
Notifications
You must be signed in to change notification settings - Fork 4
GettingStarted
Please make sure your you GWT and gwt-voices versions are compatible.
If you are using GWT version... | Then use gwt-voices version... |
---|---|
GWT 2.6.1 or newer | gwt-voices-3.3.2.jar |
GWT 2.6.0 or newer | gwt-voices-3.3.0.jar |
GWT 2.5.0 or newer | gwt-voices-3.2.0.jar |
GWT 2.4.0 or newer | gwt-voices-2.1.8.jar |
GWT 2.3.0 | gwt-voices-2.1.2.jar |
GWT 2.2.0 | gwt-voices-2.0.0.jar |
GWT 2.1.1 | gwt-voices-2.0.0.jar |
GWT 2.1.0 | gwt-voices-2.0.0.jar |
GWT 2.0 | gwt-voices-1.7.0.jar |
GWT 1.7.0 | gwt-voices-1.6.0.jar |
GWT 1.6.4 | gwt-voices-1.6.0.jar |
GWT 1.5.3 | gwt-voices-1.5.5.jar |
GWT 1.5.2 | gwt-voices-1.5.5.jar |
GWT 1.5.1 (1.5 RC2) | gwt-voices-1.5.5.jar |
GWT 1.5.0 (1.5 RC1) | gwt-voices-1.5.5.jar |
GWT 1.4.62 (1.4 update 2) | gwt-voices-1.0.0.jar |
GWT 1.4.61 (1.4 update) | gwt-voices-1.0.0.jar |
GWT 1.4.60 (1.4) | gwt-voices-1.0.0.jar |
- Play Hornet Blast or watch it on YouTube.
- Try the sound demo (source code):
- Download the latest gwt-voices-<version>.jar.
* Note for Maven users: Releases are also available in Maven Central with groupId
com.allen-sauer.gwt.voices
and artifactgwt-voices
. - Create a GWT Eclipse project as instructed here: http://www.gwtproject.org/usingeclipse.html#creating
- Add the gwt-voices jar to your project via one of these two methods:
* Right-click on the project node in the Package Explorer and select 'Build Path > Add External Archives...'. Then, specify the location of the
gwt-voices-<version>.jar
file. * Copy thegwt-voices-<version>.jar
file into your project'swar/WEB-INF/lib
directory. Then, in the Project Explorer view, right click the jar file and select 'Build Path > Add to Build Path' - Make sure the GWT compiler can find the gwt-voices source code. Modify your
*.gwt.xml
module to inherit gwt-dnd support:
<!-- Inherit sound support -->
<inherits name='com.allen_sauer.gwt.voices.gwt-voices'/>
- (Optional) if you want to play with the demo (examples), you'll need to grab those from the demo directory as there is no jar file for the demos (i.e. the
com.allen_sauer.gwt.voice.demo
package). See the Using Source with Eclipse wiki for more details.
package com.mycompany.client;
import com.google.gwt.core.client.EntryPoint;
import com.allen_sauer.gwt.voices.client.Sound;
import com.allen_sauer.gwt.voices.client.SoundController;
public class SimpleApplication implements EntryPoint {
public void onModuleLoad() {
SoundController soundController = new SoundController();
Sound sound = soundController.createSound(Sound.MIME_TYPE_AUDIO_MPEG,
"http(s)/url/to/your/sound/file.mp3");
sound.play();
}
}
package com.mycompany.client;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.DeferredCommand;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.ClickListener;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.Widget;
import com.allen_sauer.gwt.voices.client.Sound;
import com.allen_sauer.gwt.voices.client.SoundController;
import com.allen_sauer.gwt.voices.client.handler.PlaybackCompleteEvent;
import com.allen_sauer.gwt.voices.client.handler.SoundHandler;
import com.allen_sauer.gwt.voices.client.handler.SoundLoadStateChangeEvent;
public class MyApplication implements EntryPoint {
public void onModuleLoad() {
// set uncaught exception handler
GWT.setUncaughtExceptionHandler(new GWT.UncaughtExceptionHandler() {
public void onUncaughtException(Throwable throwable) {
String text = "Uncaught exception: ";
while (throwable != null) {
StackTraceElement[] stackTraceElements = throwable.getStackTrace();
text += throwable.toString() + "\n";
for (int i = 0; i < stackTraceElements.length; i++) {
text += " at " + stackTraceElements[i] + "\n";
}
throwable = throwable.getCause();
if (throwable != null) {
text += "Caused by: ";
}
}
DialogBox dialogBox = new DialogBox(true, false);
DOM.setStyleAttribute(dialogBox.getElement(), "backgroundColor", "#ABCDEF");
System.err.print(text);
text = text.replaceAll(" ", " ");
dialogBox.setHTML("<pre>" + text + "</pre>");
dialogBox.center();
}
});
// use a deferred command so that the handler catches onModuleLoad2() exceptions
DeferredCommand.addCommand(new Command() {
public void execute() {
onModuleLoad2();
}
});
}
private void onModuleLoad2() {
// create a (disabled) play button
final Button playButton = new Button("click to play");
// create a place holder for the load state
final HTML loadStateHTML = new HTML();
// create sound controller
SoundController soundController = new SoundController();
// create a sound
final Sound sound = soundController.createSound(Sound.MIME_TYPE_AUDIO_MPEG,
"url/to/your/sound/file.mp3");
// add a sound handler so we know when the sound has loaded
sound.addEventHandler(new SoundHandler() {
public void onPlaybackComplete(PlaybackCompleteEvent event) {
// WARNING: this method may in fact never be called; see Sound.LoadState
}
public void onSoundLoadStateChange(SoundLoadStateChangeEvent event) {
// See detailed documentation in Sound.LoadState
// in order to understand these possible values:
// LOAD_STATE_SUPPORTED_AND_READY
// LOAD_STATE_SUPPORTED_NOT_READY
// LOAD_STATE_SUPPORTED_MAYBE_READY
// LOAD_STATE_NOT_SUPPORTED
// LOAD_STATE_SUPPORT_NOT_KNOWN
// LOAD_STATE_UNINITIALIZED
loadStateHTML.setHTML("Load state: " + event.getLoadStateAsString());
}
});
// when we click, play the sound
playButton.addClickListener(new ClickListener() {
public void onClick(Widget sender) {
sound.play();
}
});
// add the button
RootPanel.get().add(playButton);
// add the load state status
RootPanel.get().add(loadStateHTML);
}
}
Due to browser limitations it is sometimes not possible to know if a certain sound will in fact play or has played. However, gwt-voices does provide you information on what level of detail is available for each sound file. This will vary by browser, by platform, by MIME type and by available plugins supporting audio. Here's the relevant documentation from Sound.java.
enum LoadState {
/**
* Play back of this sound's MIME type is known NOT to be supported.
* Calling {@link Sound#play()} may in rare occasions still work.
*/
LOAD_STATE_NOT_SUPPORTED,
/**
* The sound load state is unknown, and cannot be determined. Hope for the best.
* Calling {@link Sound#play()} may or may not work.
*/
LOAD_STATE_SUPPORT_NOT_KNOWN,
/**
* Play back of this sound's MIME type is supported and this sound object
* is ready for immediate play back. This means that the sound file has either
* been downloaded by the client (when not streaming), or is ready for streaming.
*/
LOAD_STATE_SUPPORTED_AND_READY,
/**
* Play back of this sound's MIME type is known to be supported, however
* the client browser is unable to provide load notification events. It
* cannot be programmatically determined when the client has downloaded
* the sound. When possible, an attempt will be made to begin downloading
* the sound file in the background. The load state will NOT change to
* {@link LoadState#LOAD_STATE_SUPPORTED_AND_READY}, or indeed to any other state.
*/
LOAD_STATE_SUPPORTED_MAYBE_READY,
/**
* Play back of this sound's MIME type is known to be supported,
* however the sound file has not yet been loaded. The load state is at some
* point expected to change to {@link LoadState#LOAD_STATE_SUPPORTED_AND_READY}.
*/
LOAD_STATE_SUPPORTED_NOT_READY,
/**
* All new sounds start in this load state, after which they will transition
* at least once to a new load state.
*/
LOAD_STATE_UNINITIALIZED,
};
gwt-voices uses one of several methods to playback audio, depending on your browser, your operating system, which extensions and plugins are installed and what the MIME Type is of the file your're trying to play. In order in which playback techniques are attempted can be influenced via code:
// Try HTML5 first
soundController.setPreferredSoundTypes(SoundType.HTML5);
// Prefer Web Audio, then try Flash, and then HTML5
soundController.setPreferredSoundTypes(SoundType.WEB_AUDIO, SoundType.FLASH, SoundType.HTML5);
or via the gwt-voices
URL query parameter, which you can appended to the end of your URLs:
- http://yourapp.com/game.html?gwt-voices=webaudio
- http://yourapp.com/game.html?gwt-voices=flash
- http://yourapp.com/game.html?gwt-voices=html5
- http://yourapp.com/game.html?gwt-voices=native
You can see all these implementations at work here:
http://allen-sauer.com/com.allen_sauer.gwt.voices.demo.VoicesDemo/VoicesDemo.html
Out of the box, Web Audio is tried first on supported browsers (currently Chrome and Webkit nightlies). Flash is tried next, because it's the next most reliable choice for audio playback. When Flash is not available, HTML5 Audio (via the AUDIO
element) is used as a fallback, or native (think BGSOUND
) browser support.
You can confirm which Audio implementation is being used by expecting the DOM after you begun using gwt-voices. You can use the Chrome Developer tools or Firebug and friends to look at the DOM.
- In the Web Audio case you'll see an empty
DIV
like this at end of the document BODY:
<div style="position: absolute; overflow: hidden; left: -500px; top: -500px; width: 0px; height: 0px; "></div>
- In the HTML5 Audio case you'll see the same empty
DIV
, followed by an AUDIO tag for each individual sound:
<div style="position: absolute; overflow: hidden; left: -500px; top: -500px; width: 0px; height: 0px; "></div>
<audio tabindex="0" src="path/to/your/foo.mp3"></audio>
<audio tabindex="0" src="path/to/your/bar.mp3"></audio>
<audio tabindex="0" src="path/to/your/funny.mp3"></audio>
<audio tabindex="0" src="path/to/your/laugh.mp3"></audio>
<audio tabindex="0" src="path/to/your/chirp.mp3"></audio>
- In the Flash case you'll see that the
DIV
contains anOBJECT
tag with idgwtVoices1000
, like this:
<div style="position: absolute; overflow: hidden; left: -500px; top: -500px; width: 0px; height: 0px; ">
<object id="gwtVoices1000" type="application/x-shockwave-flash"
data="http://chrome.angrybirds.com/fowl/gwt-voices.swf">
<param name="FlashVars" value="id=gwtVoices1000">
</object>
</div>
- In the native case you'll see that the DIV contains
OBJECT
orBGSOUND
elements for each audio file, like this:
<div style="position: absolute; overflow: hidden; left: -500px; top: -500px; width: 0px; height: 0px; ">
<object data="freesoundproject/9874__vixuxx__crow.au" autostart="true" volume="0"></object>
</div>
The advantage of using streaming to play MP3 files is that playback can begin before the entire file is downloaded by the client. There are a couple of disadvantages to streaming audio:
- The download (or audio stream) may be halted or temporarily interrupted, causing playback to be incomplete
- It's not possible to detect whether a particular audio stream exists without attempting to retrieve (playback) that stream
* Because of this, gwt-voices assumes
LOAD_STATE_SUPPORTED_AND_READY
for any streaming MP3 file when in fact there may be no such MP3 file available at the designated URL and attempting to playback the file may fail * Currently there's no way for a Sound object to indicate that download has begun. We can only detect when download is complete. As such the only way to detect the existence of an MP3 stream at a given URL is to playback/download the entire audio file, which defeats the purpose of streaming, and may in fact not be possible for 'infinite' streams.
- Make sure you use an
UncaughtExceptionHandler
so that unexpected exceptions are not lost in Production Mode