com.allen_sauer.gwt.voices.client.Html5Sound.java Source code

Java tutorial

Introduction

Here is the source code for com.allen_sauer.gwt.voices.client.Html5Sound.java

Source

/*
 * Copyright 2010 Fred Sauer
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package com.allen_sauer.gwt.voices.client;

import static com.allen_sauer.gwt.voices.client.Sound.LoadState.LOAD_STATE_NOT_SUPPORTED;
import static com.allen_sauer.gwt.voices.client.Sound.LoadState.LOAD_STATE_SUPPORTED_MAYBE_READY;
import static com.allen_sauer.gwt.voices.client.Sound.LoadState.LOAD_STATE_SUPPORT_NOT_KNOWN;

import com.google.gwt.dom.client.AudioElement;
import com.google.gwt.event.dom.client.EndedEvent;
import com.google.gwt.event.dom.client.EndedHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.media.client.Audio;
import com.google.gwt.user.client.ui.RootPanel;

import com.allen_sauer.gwt.voices.client.SoundController.MimeTypeSupport;

/**
 * Sound object representing sounds which can be played back via HTML5 audio.
 */
public class Html5Sound extends AbstractSound {
    // CHECKSTYLE_JAVADOC_OFF

    /**
     * @param mimeType the requested MIME type and optional codec according to RFC 4281
     * @return the level of support for the provided MIME type
     */
    public static MimeTypeSupport getMimeTypeSupport(String mimeType) {
        if (!Audio.isSupported()) {
            return MimeTypeSupport.MIME_TYPE_NOT_SUPPORTED;
        }
        String support = Audio.createIfSupported().getAudioElement().canPlayType(mimeType);
        assert support != null;
        if (AudioElement.CAN_PLAY_PROBABLY.equals(support)) {
            return MimeTypeSupport.MIME_TYPE_SUPPORT_READY;
        }
        if (AudioElement.CAN_PLAY_MAYBE.equals(support)) {
            return MimeTypeSupport.MIME_TYPE_SUPPORT_READY;
        }
        return MimeTypeSupport.MIME_TYPE_SUPPORT_UNKNOWN;
    }

    private Audio audio;

    private EndedHandler endedHandler = new EndedHandler() {
        @Override
        public void onEnded(EndedEvent event) {
            soundHandlerCollection.fireOnPlaybackComplete(Html5Sound.this);
        }
    };

    private HandlerRegistration endedRegistration;

    /**
     * @param mimeType the requested MIME type and optional codec according to RFC 4281
     * @param url the URL of the audio resource
     * @param streaming whether or not to stream the content, although currently ignored
     * @param crossOrigin whether or not the content is to be accessed from a different origin
     */
    public Html5Sound(String mimeType, String url, boolean streaming, boolean crossOrigin) {
        super(mimeType, url, streaming, crossOrigin);

        createAudioElement();

        MimeTypeSupport mimeTypeSupport = getMimeTypeSupport(mimeType);
        switch (mimeTypeSupport) {
        case MIME_TYPE_SUPPORT_READY:
            setLoadState(LOAD_STATE_SUPPORTED_MAYBE_READY);
            break;
        case MIME_TYPE_NOT_SUPPORTED:
            setLoadState(LOAD_STATE_NOT_SUPPORTED);
            break;
        case MIME_TYPE_SUPPORT_UNKNOWN:
            setLoadState(LOAD_STATE_SUPPORT_NOT_KNOWN);
            throw new IllegalArgumentException("unexpected MIME type support " + mimeTypeSupport);
        default:
            throw new IllegalArgumentException("unknown MIME type support " + mimeTypeSupport);
        }
    }

    @Override
    public int getBalance() {
        // not implemented
        return SoundController.DEFAULT_BALANCE;
    }

    @Override
    public boolean getLooping() {
        return audio.getAudioElement().isLoop();
    }

    @Override
    public SoundType getSoundType() {
        return SoundType.HTML5;
    }

    @Override
    public int getVolume() {
        return (int) (audio.getAudioElement().getVolume() * 100d);
    }

    @Override
    public boolean play() {
        AudioElement elem = audio.getAudioElement();
        elem.pause();
        try {
            // IE9 has been seen to throw an exception here
            elem.setCurrentTime(0);
        } catch (Exception ignore) {
        }
        if (elem.getCurrentTime() != 0) {
            /*
             * Workaround Chrome's inability to play the same audio twice:
             * http://code.google.com/p/chromium/issues/detail?id=71323
             * http://code.google.com/p/chromium/issues/detail?id=75725
             */
            createAudioElement();
        }
        elem.play();
        // best guess is that the sound played, so return true
        return true;
    }

    @Override
    public void setBalance(int balance) {
        // not implemented
    }

    @Override
    public void setLooping(boolean looping) {
        audio.getAudioElement().setLoop(looping);
    }

    @Override
    public void setVolume(int volume) {
        assert volume >= 0;
        assert volume <= 100;
        audio.getAudioElement().setVolume(volume / 100d);
    }

    @Override
    public void stop() {
        audio.getAudioElement().pause();
    }

    private void createAudioElement() {
        if (endedRegistration != null) {
            endedRegistration.removeHandler();
        }
        if (audio != null) {
            // TODO: remove, once DOM attachment no longer required to sink (bitless) events
            audio.removeFromParent();
        }
        assert Audio.isSupported();
        audio = Audio.createIfSupported();
        assert audio != null;
        AudioElement elem = audio.getAudioElement();
        assert elem != null;

        endedRegistration = audio.addEndedHandler(endedHandler);

        // TODO: remove, once DOM attachment no longer required to sink (bitless) events
        RootPanel.get().add(audio);

        if (isCrossOrigin()) {
            elem.setAttribute("crossOrigin", "anonymous");
        }
        elem.setSrc(getUrl());
    }

}