Merge "Add the HTML5Audio class, to support the audio tag." into gingerbread
This commit is contained in:
224
core/java/android/webkit/HTML5Audio.java
Normal file
224
core/java/android/webkit/HTML5Audio.java
Normal file
@@ -0,0 +1,224 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* 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 android.webkit;
|
||||
|
||||
import android.media.MediaPlayer;
|
||||
import android.media.MediaPlayer.OnBufferingUpdateListener;
|
||||
import android.media.MediaPlayer.OnCompletionListener;
|
||||
import android.media.MediaPlayer.OnErrorListener;
|
||||
import android.media.MediaPlayer.OnPreparedListener;
|
||||
import android.media.MediaPlayer.OnSeekCompleteListener;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
/**
|
||||
* <p>HTML5 support class for Audio.
|
||||
*/
|
||||
class HTML5Audio extends Handler
|
||||
implements MediaPlayer.OnBufferingUpdateListener,
|
||||
MediaPlayer.OnCompletionListener,
|
||||
MediaPlayer.OnErrorListener,
|
||||
MediaPlayer.OnPreparedListener,
|
||||
MediaPlayer.OnSeekCompleteListener {
|
||||
// Logging tag.
|
||||
private static final String LOGTAG = "HTML5Audio";
|
||||
|
||||
private MediaPlayer mMediaPlayer;
|
||||
|
||||
// The C++ MediaPlayerPrivateAndroid object.
|
||||
private int mNativePointer;
|
||||
|
||||
private static int IDLE = 0;
|
||||
private static int INITIALIZED = 1;
|
||||
private static int PREPARED = 2;
|
||||
private static int STARTED = 4;
|
||||
private static int COMPLETE = 5;
|
||||
private static int PAUSED = 6;
|
||||
private static int STOPPED = -2;
|
||||
private static int ERROR = -1;
|
||||
|
||||
private int mState = IDLE;
|
||||
|
||||
private String mUrl;
|
||||
private boolean mAskToPlay = false;
|
||||
|
||||
// Timer thread -> UI thread
|
||||
private static final int TIMEUPDATE = 100;
|
||||
|
||||
// The spec says the timer should fire every 250 ms or less.
|
||||
private static final int TIMEUPDATE_PERIOD = 250; // ms
|
||||
// The timer for timeupate events.
|
||||
// See http://www.whatwg.org/specs/web-apps/current-work/#event-media-timeupdate
|
||||
private Timer mTimer;
|
||||
private final class TimeupdateTask extends TimerTask {
|
||||
public void run() {
|
||||
HTML5Audio.this.obtainMessage(TIMEUPDATE).sendToTarget();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
switch (msg.what) {
|
||||
case TIMEUPDATE: {
|
||||
try {
|
||||
if (mState != ERROR && mMediaPlayer.isPlaying()) {
|
||||
int position = mMediaPlayer.getCurrentPosition();
|
||||
nativeOnTimeupdate(position, mNativePointer);
|
||||
}
|
||||
} catch (IllegalStateException e) {
|
||||
mState = ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// event listeners for MediaPlayer
|
||||
// Those are called from the same thread we created the MediaPlayer
|
||||
// (i.e. the webviewcore thread here)
|
||||
|
||||
// MediaPlayer.OnBufferingUpdateListener
|
||||
public void onBufferingUpdate(MediaPlayer mp, int percent) {
|
||||
nativeOnBuffering(percent, mNativePointer);
|
||||
}
|
||||
|
||||
// MediaPlayer.OnCompletionListener;
|
||||
public void onCompletion(MediaPlayer mp) {
|
||||
resetMediaPlayer();
|
||||
mState = IDLE;
|
||||
nativeOnEnded(mNativePointer);
|
||||
}
|
||||
|
||||
// MediaPlayer.OnErrorListener
|
||||
public boolean onError(MediaPlayer mp, int what, int extra) {
|
||||
mState = ERROR;
|
||||
resetMediaPlayer();
|
||||
mState = IDLE;
|
||||
return false;
|
||||
}
|
||||
|
||||
// MediaPlayer.OnPreparedListener
|
||||
public void onPrepared(MediaPlayer mp) {
|
||||
mState = PREPARED;
|
||||
if (mTimer != null) {
|
||||
mTimer.schedule(new TimeupdateTask(),
|
||||
TIMEUPDATE_PERIOD, TIMEUPDATE_PERIOD);
|
||||
}
|
||||
nativeOnPrepared(mp.getDuration(), 0, 0, mNativePointer);
|
||||
if (mAskToPlay) {
|
||||
mAskToPlay = false;
|
||||
play();
|
||||
}
|
||||
}
|
||||
|
||||
// MediaPlayer.OnSeekCompleteListener
|
||||
public void onSeekComplete(MediaPlayer mp) {
|
||||
nativeOnTimeupdate(mp.getCurrentPosition(), mNativePointer);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param nativePtr is the C++ pointer to the MediaPlayerPrivate object.
|
||||
*/
|
||||
public HTML5Audio(int nativePtr) {
|
||||
// Save the native ptr
|
||||
mNativePointer = nativePtr;
|
||||
resetMediaPlayer();
|
||||
}
|
||||
|
||||
private void resetMediaPlayer() {
|
||||
if (mMediaPlayer == null) {
|
||||
mMediaPlayer = new MediaPlayer();
|
||||
} else {
|
||||
mMediaPlayer.reset();
|
||||
}
|
||||
mMediaPlayer.setOnBufferingUpdateListener(this);
|
||||
mMediaPlayer.setOnCompletionListener(this);
|
||||
mMediaPlayer.setOnErrorListener(this);
|
||||
mMediaPlayer.setOnPreparedListener(this);
|
||||
mMediaPlayer.setOnSeekCompleteListener(this);
|
||||
|
||||
if (mTimer != null) {
|
||||
mTimer.cancel();
|
||||
}
|
||||
mTimer = new Timer();
|
||||
mState = IDLE;
|
||||
}
|
||||
|
||||
private void setDataSource(String url) {
|
||||
mUrl = url;
|
||||
try {
|
||||
if (mState != IDLE) {
|
||||
resetMediaPlayer();
|
||||
}
|
||||
mMediaPlayer.setDataSource(url);
|
||||
mState = INITIALIZED;
|
||||
mMediaPlayer.prepareAsync();
|
||||
} catch (IOException e) {
|
||||
Log.e(LOGTAG, "couldn't load the resource: " + url + " exc: " + e);
|
||||
resetMediaPlayer();
|
||||
}
|
||||
}
|
||||
|
||||
private void play() {
|
||||
if ((mState == ERROR || mState == IDLE) && mUrl != null) {
|
||||
resetMediaPlayer();
|
||||
setDataSource(mUrl);
|
||||
mAskToPlay = true;
|
||||
}
|
||||
|
||||
if (mState >= PREPARED) {
|
||||
mMediaPlayer.start();
|
||||
mState = STARTED;
|
||||
}
|
||||
}
|
||||
|
||||
private void pause() {
|
||||
if (mState == STARTED) {
|
||||
if (mTimer != null) {
|
||||
mTimer.purge();
|
||||
}
|
||||
mMediaPlayer.pause();
|
||||
mState = PAUSED;
|
||||
}
|
||||
}
|
||||
|
||||
private void seek(int msec) {
|
||||
if (mState >= PREPARED) {
|
||||
mMediaPlayer.seekTo(msec);
|
||||
}
|
||||
}
|
||||
|
||||
private void teardown() {
|
||||
mMediaPlayer.release();
|
||||
mState = ERROR;
|
||||
mNativePointer = 0;
|
||||
}
|
||||
|
||||
private float getMaxTimeSeekable() {
|
||||
return mMediaPlayer.getDuration() / 1000.0f;
|
||||
}
|
||||
|
||||
private native void nativeOnBuffering(int percent, int nativePointer);
|
||||
private native void nativeOnEnded(int nativePointer);
|
||||
private native void nativeOnPrepared(int duration, int width, int height, int nativePointer);
|
||||
private native void nativeOnTimeupdate(int position, int nativePointer);
|
||||
}
|
||||
Reference in New Issue
Block a user