287 lines
9.5 KiB
Java
Raw Normal View History

2015-11-09 17:54:15 -08:00
package com.brentvatne.react;
import android.media.MediaPlayer;
import android.os.Handler;
import android.util.Log;
2015-11-09 17:54:15 -08:00
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.uimanager.ThemedReactContext;
import com.facebook.react.uimanager.events.RCTEventEmitter;
import com.yqritc.scalablevideoview.ScalableType;
import com.yqritc.scalablevideoview.ScalableVideoView;
public class ReactVideoView extends ScalableVideoView implements MediaPlayer.OnPreparedListener, MediaPlayer
.OnErrorListener, MediaPlayer.OnBufferingUpdateListener, MediaPlayer.OnCompletionListener {
public enum Events {
EVENT_LOAD_START("onVideoLoadStart"),
EVENT_LOAD("onVideoLoad"),
EVENT_ERROR("onVideoError"),
EVENT_PROGRESS("onVideoProgress"),
EVENT_SEEK("onVideoSeek"),
EVENT_END("onVideoEnd");
private final String mName;
Events(final String name) {
mName = name;
}
@Override
public String toString() {
return mName;
}
}
2015-11-09 17:54:15 -08:00
public static final String EVENT_PROP_FAST_FORWARD = "canPlayFastForward";
public static final String EVENT_PROP_SLOW_FORWARD = "canPlaySlowForward";
public static final String EVENT_PROP_SLOW_REVERSE = "canPlaySlowReverse";
public static final String EVENT_PROP_REVERSE = "canPlayReverse";
public static final String EVENT_PROP_STEP_FORWARD = "canStepForward";
public static final String EVENT_PROP_STEP_BACKWARD = "canStepBackward";
2015-11-13 16:06:42 -08:00
public static final String EVENT_PROP_DURATION = "duration";
public static final String EVENT_PROP_PLAYABLE_DURATION = "playableDuration";
public static final String EVENT_PROP_CURRENT_TIME = "currentTime";
public static final String EVENT_PROP_SEEK_TIME = "seekTime";
2015-11-13 16:06:42 -08:00
public static final String EVENT_PROP_ERROR = "error";
public static final String EVENT_PROP_WHAT = "what";
public static final String EVENT_PROP_EXTRA = "extra";
2015-11-09 17:54:15 -08:00
private ThemedReactContext mThemedReactContext;
private RCTEventEmitter mEventEmitter;
2015-11-09 17:54:15 -08:00
private Handler mProgressUpdateHandler = new Handler();
private Runnable mProgressUpdateRunnable = null;
2015-11-13 16:56:40 -08:00
private String mSrcUriString = null;
private String mSrcType = "mp4";
private boolean mSrcIsNetwork = false;
2015-11-09 17:54:15 -08:00
private ScalableType mResizeMode = ScalableType.LEFT_TOP;
private boolean mRepeat = false;
private boolean mPaused = false;
private boolean mMuted = false;
private float mVolume = 1.0f;
private float mRate = 1.0f;
2015-11-09 17:54:15 -08:00
2015-11-13 16:06:42 -08:00
private boolean mMediaPlayerValid = false; // True if mMediaPlayer is in prepared, started, or paused state.
private int mVideoDuration = 0;
private int mVideoBufferedDuration = 0;
2015-11-13 16:06:42 -08:00
2015-11-09 17:54:15 -08:00
public ReactVideoView(ThemedReactContext themedReactContext) {
super(themedReactContext);
mThemedReactContext = themedReactContext;
mEventEmitter = themedReactContext.getJSModule(RCTEventEmitter.class);
2015-11-09 17:54:15 -08:00
initializeMediaPlayerIfNeeded();
2015-11-09 17:54:15 -08:00
setSurfaceTextureListener(this);
mProgressUpdateRunnable = new Runnable() {
@Override
public void run() {
2015-11-13 16:06:42 -08:00
if (mMediaPlayerValid) {
WritableMap event = Arguments.createMap();
event.putDouble(EVENT_PROP_CURRENT_TIME, mMediaPlayer.getCurrentPosition() / 1000.0);
event.putDouble(EVENT_PROP_PLAYABLE_DURATION, mVideoBufferedDuration / 1000.0); //TODO:mBufferUpdateRunnable
mEventEmitter.receiveEvent(getId(), Events.EVENT_PROGRESS.toString(), event);
2015-11-09 17:54:15 -08:00
}
mProgressUpdateHandler.postDelayed(mProgressUpdateRunnable, 250);
}
};
mProgressUpdateHandler.post(mProgressUpdateRunnable);
}
private void initializeMediaPlayerIfNeeded() {
if (mMediaPlayer == null) {
2015-11-13 16:06:42 -08:00
mMediaPlayerValid = false;
mMediaPlayer = new MediaPlayer();
mMediaPlayer.setScreenOnWhilePlaying(true);
mMediaPlayer.setOnVideoSizeChangedListener(this);
mMediaPlayer.setOnErrorListener(this);
mMediaPlayer.setOnPreparedListener(this);
mMediaPlayer.setOnBufferingUpdateListener(this);
2015-11-12 19:27:12 -08:00
mMediaPlayer.setOnCompletionListener(this);
}
2015-11-09 17:54:15 -08:00
}
2015-11-13 16:56:40 -08:00
public void setSrc(final String uriString, final String type, final boolean isNetwork) {
mSrcUriString = uriString;
mSrcType = type;
mSrcIsNetwork = isNetwork;
2015-11-13 16:06:42 -08:00
mMediaPlayerValid = false;
mVideoDuration = 0;
mVideoBufferedDuration = 0;
2015-11-13 16:06:42 -08:00
initializeMediaPlayerIfNeeded();
mMediaPlayer.reset();
2015-11-12 19:27:12 -08:00
2015-11-13 16:56:40 -08:00
try {
if (isNetwork) {
setDataSource(uriString);
} else {
setRawData(mThemedReactContext.getResources().getIdentifier(
uriString,
"raw",
mThemedReactContext.getPackageName()
));
}
} catch (Exception e) {
e.printStackTrace();
return;
2015-11-12 19:27:12 -08:00
}
2015-11-13 16:56:40 -08:00
WritableMap src = Arguments.createMap();
src.putString(ReactVideoViewManager.PROP_SRC_URI, uriString);
src.putString(ReactVideoViewManager.PROP_SRC_TYPE, type);
src.putBoolean(ReactVideoViewManager.PROP_SRC_IS_NETWORK, isNetwork);
WritableMap event = Arguments.createMap();
event.putMap(ReactVideoViewManager.PROP_SRC, src);
mEventEmitter.receiveEvent(getId(), Events.EVENT_LOAD_START.toString(), event);
prepareAsync(this);
2015-11-12 19:27:12 -08:00
}
2015-11-09 17:54:15 -08:00
public void setResizeModeModifier(final ScalableType resizeMode) {
mResizeMode = resizeMode;
2015-11-13 16:06:42 -08:00
if (mMediaPlayerValid) {
setScalableType(resizeMode);
invalidate();
}
2015-11-09 17:54:15 -08:00
}
public void setRepeatModifier(final boolean repeat) {
mRepeat = repeat;
2015-11-13 16:06:42 -08:00
if (mMediaPlayerValid) {
setLooping(repeat);
}
2015-11-09 17:54:15 -08:00
}
public void setPausedModifier(final boolean paused) {
mPaused = paused;
2015-11-13 16:06:42 -08:00
if (!mMediaPlayerValid) {
return;
}
2015-11-13 16:06:42 -08:00
if (mPaused) {
if (mMediaPlayer.isPlaying()) {
2015-11-09 17:54:15 -08:00
pause();
}
2015-11-13 16:06:42 -08:00
} else {
if (!mMediaPlayer.isPlaying()) {
start();
}
2015-11-09 17:54:15 -08:00
}
}
public void setMutedModifier(final boolean muted) {
mMuted = muted;
2015-11-13 16:06:42 -08:00
if (!mMediaPlayerValid) {
return;
}
2015-11-09 17:54:15 -08:00
if (mMuted) {
setVolume(0, 0);
} else {
setVolume(mVolume, mVolume);
}
}
public void setVolumeModifier(final float volume) {
mVolume = volume;
setMutedModifier(mMuted);
}
public void setRateModifier(final float rate) {
mRate = rate;
if (mMediaPlayerValid) {
// TODO: Implement this.
Log.e(ReactVideoViewManager.REACT_CLASS, "Setting playback rate is not yet supported on Android");
}
}
2015-11-09 17:54:15 -08:00
public void applyModifiers() {
setResizeModeModifier(mResizeMode);
setRepeatModifier(mRepeat);
setPausedModifier(mPaused);
2015-11-13 16:06:42 -08:00
setMutedModifier(mMuted);
// setRateModifier(mRate);
2015-11-09 17:54:15 -08:00
}
@Override
public void onPrepared(MediaPlayer mp) {
2015-11-13 16:06:42 -08:00
mMediaPlayerValid = true;
mVideoDuration = mp.getDuration();
WritableMap event = Arguments.createMap();
2015-11-13 16:06:42 -08:00
event.putDouble(EVENT_PROP_DURATION, mVideoDuration / 1000.0);
event.putDouble(EVENT_PROP_CURRENT_TIME, mp.getCurrentPosition() / 1000.0);
// TODO: Actually check if you can.
event.putBoolean(EVENT_PROP_FAST_FORWARD, true);
event.putBoolean(EVENT_PROP_SLOW_FORWARD, true);
event.putBoolean(EVENT_PROP_SLOW_REVERSE, true);
event.putBoolean(EVENT_PROP_REVERSE, true);
event.putBoolean(EVENT_PROP_FAST_FORWARD, true);
event.putBoolean(EVENT_PROP_STEP_BACKWARD, true);
event.putBoolean(EVENT_PROP_STEP_FORWARD, true);
mEventEmitter.receiveEvent(getId(), Events.EVENT_LOAD.toString(), event);
applyModifiers();
}
@Override
public boolean onError(MediaPlayer mp, int what, int extra) {
WritableMap error = Arguments.createMap();
2015-11-13 16:06:42 -08:00
error.putInt(EVENT_PROP_WHAT, what);
error.putInt(EVENT_PROP_EXTRA, extra);
WritableMap event = Arguments.createMap();
2015-11-13 16:06:42 -08:00
event.putMap(EVENT_PROP_ERROR, error);
mEventEmitter.receiveEvent(getId(), Events.EVENT_ERROR.toString(), event);
return true;
}
@Override
public void onBufferingUpdate(MediaPlayer mp, int percent) {
mVideoBufferedDuration = (int) Math.round((double) (mVideoDuration * percent) / 100.0);
}
@Override
public void seekTo(int msec) {
if (mMediaPlayerValid) {
WritableMap event = Arguments.createMap();
event.putDouble(EVENT_PROP_CURRENT_TIME, getCurrentPosition() / 1000.0);
event.putDouble(EVENT_PROP_SEEK_TIME, msec / 1000.0);
mEventEmitter.receiveEvent(getId(), Events.EVENT_SEEK.toString(), event);
super.seekTo(msec);
}
}
@Override
public void onCompletion(MediaPlayer mp) {
2015-11-13 16:06:42 -08:00
mMediaPlayerValid = false;
mEventEmitter.receiveEvent(getId(), Events.EVENT_END.toString(), null);
}
2015-11-13 16:06:42 -08:00
@Override
protected void onDetachedFromWindow() {
mMediaPlayerValid = false;
super.onDetachedFromWindow();
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
2015-11-13 16:56:40 -08:00
setSrc(mSrcUriString, mSrcType, mSrcIsNetwork);
2015-11-13 16:06:42 -08:00
}
2015-11-09 17:54:15 -08:00
}