package com.sound.ampache.utility; /* Copyright (c) 2010 ABAAKOUK Mehdi <theli48@gmail.com> * * For the PhoneStateListener: * Copyright (c) 2008 Kevin James Purdy <purdyk@onid.orst.edu> * * Amdroid Port: * Copyright (c) 2010 Jacob Alexander < haata@users.sf.net > * Copyrigth (c) 2010 Michael Gapczynski <GapczynskiM@gmail.com> * * +------------------------------------------------------------------------+ * | This program is free software; you can redistribute it and/or | * | modify it under the terms of the GNU General Public License | * | as published by the Free Software Foundation; either version 2 | * | of the License, or (at your option) any later version. | * | | * | This program is distributed in the hope that it will be useful, | * | but WITHOUT ANY WARRANTY; without even the implied warranty of | * | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | * | GNU General Public License for more details. | * | | * | You should have received a copy of the GNU General Public License | * | along with this program; if not, write to the Free Software | * | Foundation, Inc., 59 Temple Place - Suite 330, | * | Boston, MA 02111-1307, USA. | * +------------------------------------------------------------------------+ */ import android.content.Context; import android.media.AudioManager; import android.media.MediaPlayer; import android.telephony.PhoneStateListener; import android.telephony.TelephonyManager; import android.util.Log; import com.sound.ampache.objects.Media; import com.sound.ampache.objects.Song; import com.sound.ampache.objects.Video; import java.util.ArrayList; public class Player { private MediaPlayer mPlayer; private Playlist mPlaylist; private static String TAG = "AmdroidPlayer"; private Song mSong; private Video mVideo; private int mBuffering = -1; private Boolean mPlayAfterPrepared = true; private enum STATE { Idle, Initialised, Prepared, Started, Paused, Stopped } private STATE mState; private Context mContext; private MyPhoneStateListener mPhoneStateListener; private MyMediaPlayerListener mMediaPlayerListener; private ArrayList<PlayerListener> mPlayerListeners; private String authToken; public interface PlayerListener { void onTogglePlaying(boolean playing); void onPlayerStopped(); void onNewMediaPlaying(Media media); void onVideoSizeChanged(int width, int height); void onBuffering(int buffer); void onSeek(int position); void onError(int what, int extra); } public Player(Context context, Playlist playlist) { mContext = context; mPlaylist = playlist; mPhoneStateListener = new MyPhoneStateListener(); mPlayerListeners = new ArrayList<PlayerListener>(); mMediaPlayerListener = new MyMediaPlayerListener(); // Prepare Android Media Player mPlayer = new MediaPlayer(); mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); // Setting up Media Player Listeners mPlayer.setOnBufferingUpdateListener(mMediaPlayerListener); mPlayer.setOnCompletionListener(mMediaPlayerListener); mPlayer.setOnErrorListener(mMediaPlayerListener); mPlayer.setOnInfoListener(mMediaPlayerListener); mPlayer.setOnPreparedListener(mMediaPlayerListener); mPlayer.setOnSeekCompleteListener(mMediaPlayerListener); mPlayer.setOnVideoSizeChangedListener(mMediaPlayerListener); setState(STATE.Idle); } public void stop() { for (PlayerListener obj : mPlayerListeners) { obj.onPlayerStopped(); } mPlayer.stop(); mPlayer.reset(); setState(STATE.Stopped); } private void setState(STATE state) { mState = state; for (PlayerListener obj : mPlayerListeners) { obj.onTogglePlaying(isPlaying()); } String st = ""; switch (state) { case Idle: st = "Idle"; break; case Initialised: st = "Initialised"; break; case Prepared: st = "Prepared"; break; case Started: st = "Started"; break; case Paused: st = "Paused"; break; case Stopped: st = "Stopped"; break; default: st = "Unknown"; break; } Log.v(TAG, "setState(" + st + ")"); } private void updateBuffer(int buffer) { mBuffering = buffer; for (PlayerListener obj : mPlayerListeners) { obj.onBuffering(mBuffering); } } public int getBuffer() { return mBuffering; } public void playMedia(Media media) { if (media == null) { Log.w(TAG, "Null input, cannot playMedia()."); return; } if ("Song".equals(media.getType())) { playSong((Song) media); } else if ("Video".equals(media.getType())) { playVideo((Video) media); } else { Log.e(TAG, "Invalid Media Type: " + media.getType()); } } public void playSong(Song song) { setState(STATE.Idle); String uri = song.liveUrl(authToken); Log.v(TAG, "Playing uri: " + uri); if (mState == STATE.Prepared || mState == STATE.Started || mState == STATE.Paused) { mPlayer.stop(); } mPlayAfterPrepared = true; mSong = song; updateBuffer(-1); for (PlayerListener obj : mPlayerListeners) { obj.onNewMediaPlaying((Media) mSong); } mPlayer.reset(); try { mPlayer.setDataSource(uri); setState(STATE.Initialised); mPlayer.prepareAsync(); } catch (Exception blah) { return; } } public void playVideo(Video video) { setState(STATE.Idle); String uri = video.liveUrl(authToken); Log.v(TAG, "Playing uri: " + uri); if (mState == STATE.Prepared || mState == STATE.Started || mState == STATE.Paused) { mPlayer.stop(); } mPlayAfterPrepared = true; mVideo = video; updateBuffer(-1); for (PlayerListener obj : mPlayerListeners) { obj.onNewMediaPlaying((Media) mVideo); } mPlayer.reset(); try { mPlayer.setDataSource(uri); setState(STATE.Initialised); mPlayer.prepareAsync(); } catch (Exception blah) { return; } } public void doPauseResume() { if (mState == STATE.Started || mState == STATE.Paused) { if (mPlayer.isPlaying()) { mPlayer.pause(); setState(STATE.Paused); } else { mPlayer.start(); setState(STATE.Started); } } else if (mState == STATE.Initialised) { mPlayAfterPrepared = !mPlayAfterPrepared; } else if (mState == STATE.Prepared) { mPlayer.start(); setState(STATE.Started); } } public void seekTo(int position) { if (mState == STATE.Prepared || mState == STATE.Started || mState == STATE.Paused) { mPlayer.seekTo(position); } } public boolean isSeekable() { return mState == STATE.Prepared || mState == STATE.Started || mState == STATE.Paused; } public boolean isPlaying() { return (mState == STATE.Initialised && mPlayAfterPrepared) || mState == STATE.Started; } public int getCurrentPosition() { if (mState == STATE.Prepared || mState == STATE.Started || mState == STATE.Paused) { return mPlayer.getCurrentPosition(); } else { return 0; } } public int getDuration() { if (mState == STATE.Initialised || mState == STATE.Prepared || mState == STATE.Started || mState == STATE.Paused) { try { return Integer.parseInt(mSong.time) * 1000; } catch (Exception poo) { } if (mState != STATE.Initialised) { return mPlayer.getDuration(); } } return 0; } public void quit() { TelephonyManager tmgr = (TelephonyManager) mContext .getSystemService(Context.TELEPHONY_SERVICE); tmgr.listen(mPhoneStateListener, 0); } public void setAuthToken(String authToken) { this.authToken = authToken; } public void setPlayerListener(PlayerListener StatusChangeObject) { mPlayerListeners.add(StatusChangeObject); } private class MyMediaPlayerListener implements MediaPlayer.OnBufferingUpdateListener, MediaPlayer.OnCompletionListener, MediaPlayer.OnErrorListener, MediaPlayer.OnInfoListener, MediaPlayer.OnPreparedListener, MediaPlayer.OnSeekCompleteListener, MediaPlayer.OnVideoSizeChangedListener { public void onBufferingUpdate(MediaPlayer mp, int buffer) { updateBuffer(buffer); } public void onCompletion(MediaPlayer mp) { mSong = null; mVideo = null; mPlayer.stop(); setState(STATE.Stopped); Log.v(TAG, "Completion"); Media media = mPlaylist.next(); if (media == null) { for (PlayerListener obj : mPlayerListeners) { obj.onPlayerStopped(); } mPlayer.stop(); mPlayer.reset(); setState(STATE.Stopped); return; } playMedia(media); } public boolean onError(MediaPlayer mp, int what, int extra) { Log.e(TAG, "Player error (" + what + ", " + extra + ")"); for (PlayerListener obj : mPlayerListeners) { obj.onError(what, extra); } return true; } public boolean onInfo(MediaPlayer mp, int what, int extra) { Log.d(TAG, "Player info (" + what + ", " + extra + ")"); return true; } public void onPrepared(MediaPlayer mp) { setState(STATE.Prepared); if (mPlayAfterPrepared) { mPlayer.start(); setState(STATE.Started); } mPlayAfterPrepared = true; } public void onSeekComplete(MediaPlayer mp) { for (PlayerListener obj : mPlayerListeners) { obj.onSeek(mp.getCurrentPosition()); } } public void onVideoSizeChanged(MediaPlayer mp, int width, int height) { for (PlayerListener obj : mPlayerListeners) { obj.onVideoSizeChanged(width, height); } } } // Handle phone calls private class MyPhoneStateListener extends PhoneStateListener { private Boolean mResumeAfterCall = false; @Override public void onCallStateChanged(int state, String incomingNumber) { if (state == TelephonyManager.CALL_STATE_RINGING) { AudioManager audioManager = (AudioManager) mContext .getSystemService(Context.AUDIO_SERVICE); int ringvolume = audioManager .getStreamVolume(AudioManager.STREAM_RING); if (ringvolume > 0) { mResumeAfterCall = (mPlayer.isPlaying() || mResumeAfterCall); mPlayer.pause(); } } else if (state == TelephonyManager.CALL_STATE_OFFHOOK) { // pause the music while a conversation is in progress mResumeAfterCall = (mPlayer.isPlaying() || mResumeAfterCall); mPlayer.pause(); } else if (state == TelephonyManager.CALL_STATE_IDLE) { // start playing again if (mResumeAfterCall) { // resume playback only if music was playing // when the call was answered mPlayer.start(); mResumeAfterCall = false; } } } } ; }