package org.wikipedia.media; import android.media.MediaPlayer; import android.support.annotation.NonNull; import org.wikipedia.util.StringUtil; import org.wikipedia.util.log.L; import java.io.IOException; public class MediaPlayerImplementation implements AvPlayerImplementation { private static final boolean VERBOSE = false; @NonNull private final MediaPlayer player = new MediaPlayer(); @Override public void deinit() { if (VERBOSE) { L.v("Releasing"); } player.release(); } @Override public void init() { } @Override public void load(@NonNull String path, @NonNull AvPlayer.Callback callback, @NonNull AvPlayer.ErrorCallback errorCallback) { load(path, new PreparedListenerCallbackWrapper(callback), new ErrorListenerErrorCallbackWrapper(errorCallback)); } @Override public void stop() { if (VERBOSE) { L.v("Stopping"); } // Do not call MediaPlayer.stop(). This requires going through the whole lifecycle again. // Also, seek triggers playback, so call before pausing. player.seekTo(0); pause(); } @Override public void play(@NonNull AvPlayer.Callback callback, @NonNull AvPlayer.ErrorCallback errorCallback) { play(new CompletionListenerCallbackWrapper(callback), new ErrorListenerErrorCallbackWrapper(errorCallback)); } @Override public void pause() { if (VERBOSE) { L.v("Pausing"); } player.pause(); } private void load(@NonNull String path, @NonNull MediaPlayer.OnPreparedListener listener, @NonNull MediaPlayer.OnErrorListener errorListener) { if (VERBOSE) { L.v("Loading path=" + path); } player.reset(); player.setOnPreparedListener(listener); player.setOnErrorListener(errorListener); if (setDataSource(path)) { player.prepareAsync(); } else { errorListener.onError(player, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); } } private void play(@NonNull MediaPlayer.OnCompletionListener listener, @NonNull MediaPlayer.OnErrorListener errorListener) { if (VERBOSE) { L.v("Playing"); } player.setOnCompletionListener(listener); player.setOnErrorListener(errorListener); player.start(); } private boolean setDataSource(@NonNull String path) { try { player.setDataSource(path); return true; } catch (IOException e) { L.d(e); return false; } } private abstract static class CallbackWrapper { @NonNull private final AvPlayer.Callback callback; CallbackWrapper(@NonNull AvPlayer.Callback callback) { this.callback = callback; } protected void onSuccess() { callback.onSuccess(); } } private abstract static class ErrorCallbackWrapper { @NonNull private final AvPlayer.ErrorCallback errorCallback; ErrorCallbackWrapper(@NonNull AvPlayer.ErrorCallback errorCallback) { this.errorCallback = errorCallback; } protected void onError() { errorCallback.onError(); } } private static class PreparedListenerCallbackWrapper extends CallbackWrapper implements MediaPlayer.OnPreparedListener { PreparedListenerCallbackWrapper(@NonNull AvPlayer.Callback callback) { super(callback); } @Override public void onPrepared(MediaPlayer player) { if (VERBOSE) { L.v("Loaded"); } onSuccess(); } } private static class CompletionListenerCallbackWrapper extends CallbackWrapper implements MediaPlayer.OnCompletionListener { CompletionListenerCallbackWrapper(@NonNull AvPlayer.Callback callback) { super(callback); } @Override public void onCompletion(MediaPlayer mp) { if (VERBOSE) { L.v("Stopped"); } onSuccess(); } } private static class ErrorListenerErrorCallbackWrapper extends ErrorCallbackWrapper implements MediaPlayer.OnErrorListener { ErrorListenerErrorCallbackWrapper(@NonNull AvPlayer.ErrorCallback errorCallback) { super(errorCallback); } @Override public boolean onError(MediaPlayer mp, int what, int extra) { if (VERBOSE) { L.v("Error: what=" + StringUtil.intToHexStr(what) + " extra=" + StringUtil.intToHexStr(extra)); } onError(); return true; } } }