package com.simplecity.amp_library.playback; import android.media.AudioManager; import android.media.MediaPlayer; import android.net.Uri; import android.os.Handler; import android.os.PowerManager; import android.text.TextUtils; import android.util.Log; import com.crashlytics.android.core.CrashlyticsCore; import java.lang.ref.WeakReference; /** * Provides a unified interface for dealing with midi files and other media * files. */ class MultiPlayer implements MediaPlayer.OnErrorListener, MediaPlayer.OnCompletionListener { private static final String TAG = "MultiPlayer"; private final WeakReference<MusicService> mService; private MediaPlayer mCurrentMediaPlayer = new MediaPlayer(); private MediaPlayer mNextMediaPlayer; private Handler mHandler; private boolean mIsInitialized = false; MultiPlayer(final MusicService service) { mService = new WeakReference<>(service); mCurrentMediaPlayer.setWakeMode(mService.get(), PowerManager.PARTIAL_WAKE_LOCK); } void setDataSource(final String path) { mIsInitialized = setDataSourceImpl(mCurrentMediaPlayer, path); if (mIsInitialized) { setNextDataSource(null); } } private boolean setDataSourceImpl(final MediaPlayer mediaPlayer, final String path) { if (TextUtils.isEmpty(path) || mediaPlayer == null) { return false; } try { mediaPlayer.reset(); mediaPlayer.setOnPreparedListener(null); if (path.startsWith("content://")) { Uri uri = Uri.parse(path); mediaPlayer.setDataSource(mService.get(), uri); } else { mediaPlayer.setDataSource(path); } mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); mediaPlayer.prepare(); } catch (final Exception e) { Log.e(TAG, "setDataSource failed: " + e.getLocalizedMessage()); CrashlyticsCore.getInstance().log("setDataSourceImpl failed. Path: [" + path + "] error: " + e.getLocalizedMessage()); return false; } mediaPlayer.setOnCompletionListener(this); mediaPlayer.setOnErrorListener(this); return true; } void setNextDataSource(final String path) { try { mCurrentMediaPlayer.setNextMediaPlayer(null); } catch (IllegalArgumentException e) { Log.e(TAG, "Next media player is current one, continuing"); } catch (IllegalStateException e) { Log.e(TAG, "Media player not initialized!"); CrashlyticsCore.getInstance().log("setNextDataSource failed for. Media player not intitialized."); return; } if (mNextMediaPlayer != null) { mNextMediaPlayer.release(); mNextMediaPlayer = null; } if (TextUtils.isEmpty(path)) { return; } mNextMediaPlayer = new MediaPlayer(); mNextMediaPlayer.setWakeMode(mService.get(), PowerManager.PARTIAL_WAKE_LOCK); mNextMediaPlayer.setAudioSessionId(getAudioSessionId()); if (setDataSourceImpl(mNextMediaPlayer, path)) { try { mCurrentMediaPlayer.setNextMediaPlayer(mNextMediaPlayer); } catch (Exception e) { Log.e(TAG, "setNextDataSource failed - failed to call setNextMediaPlayer on mCurrentMediaPlayer. Error: " + e.getLocalizedMessage()); CrashlyticsCore.getInstance().log("setNextDataSource failed - failed to call setNextMediaPlayer on mCurrentMediaPlayer. Error: " + e.getLocalizedMessage()); if (mNextMediaPlayer != null) { mNextMediaPlayer.release(); mNextMediaPlayer = null; } } } else { Log.e(TAG, "setDataSourceImpl failed for path: [" + path + "]. Setting next media player to null"); CrashlyticsCore.getInstance().log("setDataSourceImpl failed for path: [" + path + "]. Setting next media player to null"); if (mNextMediaPlayer != null) { mNextMediaPlayer.release(); mNextMediaPlayer = null; } } } boolean isInitialized() { return mIsInitialized; } public void start() { try { mCurrentMediaPlayer.start(); } catch (RuntimeException e) { CrashlyticsCore.getInstance().log("MusicService.start() failed. Exception: " + e.toString()); } } public void stop() { try { mCurrentMediaPlayer.reset(); } catch (IllegalStateException e) { Log.e(TAG, "Error stopping MultiPlayer: " + e.getLocalizedMessage()); CrashlyticsCore.getInstance().log("stop() failed. Error: " + e.getLocalizedMessage()); } mIsInitialized = false; } /** * You CANNOT use this player anymore after calling release() */ public void release() { stop(); mCurrentMediaPlayer.release(); } public void pause() { try { mCurrentMediaPlayer.pause(); } catch (IllegalStateException e) { Log.e(TAG, "Error pausing MultiPlayer: " + e.getLocalizedMessage()); } } public void setHandler(Handler handler) { mHandler = handler; } public long getDuration() { try { return mCurrentMediaPlayer.getDuration(); } catch (IllegalStateException ignored) { return 0; } } public long getPosition() { try { return mCurrentMediaPlayer.getCurrentPosition(); } catch (IllegalStateException ignored) { return 0; } } long seekTo(long whereto) { try { mCurrentMediaPlayer.seekTo((int) whereto); } catch (IllegalStateException e) { Log.e(TAG, "Error seeking MultiPlayer: " + e.getLocalizedMessage()); } return whereto; } void setVolume(float vol) { try { mCurrentMediaPlayer.setVolume(vol, vol); } catch (IllegalStateException e) { Log.e(TAG, "Error setting MultiPlayer volume: " + e.getLocalizedMessage()); } } int getAudioSessionId() { int sessionId = 0; try { sessionId = mCurrentMediaPlayer.getAudioSessionId(); } catch (IllegalStateException ignored) { //Nothing to do } return sessionId; } @Override public boolean onError(final MediaPlayer mp, final int what, final int extra) { switch (what) { case MediaPlayer.MEDIA_ERROR_SERVER_DIED: mIsInitialized = false; mCurrentMediaPlayer.release(); mCurrentMediaPlayer = new MediaPlayer(); mCurrentMediaPlayer.setWakeMode(mService.get(), PowerManager.PARTIAL_WAKE_LOCK); mHandler.sendMessageDelayed(mHandler.obtainMessage(MusicService.PlayerHandler.SERVER_DIED), 2000); return true; default: break; } return false; } @Override public void onCompletion(final MediaPlayer mp) { if (mp == mCurrentMediaPlayer && mNextMediaPlayer != null) { mCurrentMediaPlayer.release(); mCurrentMediaPlayer = mNextMediaPlayer; mNextMediaPlayer = null; mHandler.sendEmptyMessage(MusicService.PlayerHandler.TRACK_WENT_TO_NEXT); } else { mService.get().mWakeLock.acquire(30000); mHandler.sendEmptyMessage(MusicService.PlayerHandler.TRACK_ENDED); mHandler.sendEmptyMessage(MusicService.PlayerHandler.RELEASE_WAKELOCK); } } }