content: /*
   * Copyright (C) 2012 YIXIA.COM
   *
   * 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 com.cjj.bb.view;
  
  import io.vov.vitamio.MediaPlayer;
  import io.vov.vitamio.MediaPlayer.OnBufferingUpdateListener;
  import io.vov.vitamio.MediaPlayer.OnCompletionListener;
  import io.vov.vitamio.MediaPlayer.OnErrorListener;
  import io.vov.vitamio.MediaPlayer.OnHWRenderFailedListener;
  import io.vov.vitamio.MediaPlayer.OnInfoListener;
  import io.vov.vitamio.MediaPlayer.OnPreparedListener;
  import io.vov.vitamio.MediaPlayer.OnSeekCompleteListener;
  import io.vov.vitamio.MediaPlayer.OnTimedTextListener;
  import io.vov.vitamio.MediaPlayer.OnVideoSizeChangedListener;
  import io.vov.vitamio.Vitamio;
  import io.vov.vitamio.utils.Log;
  
  import java.io.File;
  import java.io.IOException;
  import java.util.ArrayList;
  
  import android.app.Service;
  import android.content.Context;
  import android.content.Intent;
  import android.graphics.Bitmap;
  import android.net.Uri;
  import android.os.Binder;
  import android.os.IBinder;
  import android.telephony.PhoneStateListener;
  import android.telephony.TelephonyManager;
  import android.view.SurfaceHolder;
  
  import com.cjj.bb.utils.Logger;
  
  
  public class PlayerService extends Service implements
  		OnBufferingUpdateListener, OnCompletionListener, OnPreparedListener,
  		OnVideoSizeChangedListener, OnErrorListener, OnInfoListener,
  		OnSeekCompleteListener, OnTimedTextListener {
  	private MediaPlayer mPlayer;
  	private VPlayerListener mListener;
  	private Uri mUri;
  	private Uri mOldUri;
  	private float mSeekTo = -1f;
  	private boolean mFromNotification;
  	private String[] mSubPaths;
  	private boolean mInitialized;
  	private final IBinder mBinder = new LocalBinder();
  	private TelephonyManager mTelephonyManager;
  	private int mCurrentState;
  	private SurfaceHolder mSurfaceHolder;
  	public static final int VPLYAER_NOTIFICATION_ID = 1;
  
  	public static final int STATE_PREPARED = -1;
  	public static final int STATE_PLAYING = 0;
  	public static final int STATE_NEED_RESUME = 1;
  	public static final int STATE_STOPPED = 2;
  	public static final int STATE_RINGING = 3;
  
  	private int mLastAudioTrack = -1;
  	private String mLastSubTrack;
  	private int mLastSubTrackId = -1;
  	private long mMediaId = -1l;
  
  	public class LocalBinder extends Binder {
  		public PlayerService getService() {
  			return PlayerService.this;
  		}
  	}
  
  	@Override
  	public void onCreate() {
  		super.onCreate();
  		mInitialized = false;
  		mTelephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
  		mTelephonyManager.listen(mPhoneListener,
  				PhoneStateListener.LISTEN_CALL_STATE);
  
  	}
  
  	@Override
  	public int onStartCommand(Intent intent, int flags, int startId) {
  		if (Vitamio.isInitialized(this)) {
  			vplayerInit(intent.getBooleanExtra("isHWCodec", false));
  		} else {
  			stopSelf();
  		}
  		Log.d("CREATE OK");
  		return super.onStartCommand(intent, flags, startId);
  	}
  
  	private void vplayerInit(boolean isHWCodec) {
  		mPlayer = new MediaPlayer(PlayerService.this.getApplicationContext(),
  				isHWCodec);
  		mPlayer.setOnHWRenderFailedListener(new OnHWRenderFailedListener() {
  			@Override
  			public void onFailed() {
  				if (mListener != null)
  					mListener.onHWRenderFailed();
  			}
  		});
  		mPlayer.setOnBufferingUpdateListener(PlayerService.this);
  		mPlayer.setOnCompletionListener(PlayerService.this);
  		mPlayer.setOnPreparedListener(PlayerService.this);
  		mPlayer.setOnVideoSizeChangedListener(PlayerService.this);
  		mPlayer.setOnErrorListener(PlayerService.this);
  		mPlayer.setOnInfoListener(PlayerService.this);
  	}
  
  	public void releaseContext() {
  		if (mPlayer != null)
  			mPlayer.release();
  		mPlayer = null;
  	}
  
  	@Override
  	public IBinder onBind(Intent intent) {
  		Log.d("BIND OK : " + intent.getPackage());
  		return mBinder;
  	}
  
  	@Override
  	public void onDestroy() {
  		super.onDestroy();
  		release(true);
  		releaseContext();
  	}
  
  	public boolean isInitialized() {
  		return mInitialized;
  	}
  
  	private String mTitle;
  
  	public boolean initialize(Uri filePath, String displayName,
  			boolean saveUri, float startPos, VPlayerListener listener,
  			int parentId, boolean isHWCodec) {
  		if (mPlayer == null)
  			vplayerInit(isHWCodec);
  		mTitle = displayName;
  		mListener = listener;
  		mOldUri = mUri;
  		mUri = filePath;
  		mSeekTo = startPos;
  		mMediaId = -1;
  		mLastAudioTrack = -1;
  		mLastSubTrackId = -1;
  		mLastSubTrack = "";
  		setMediaTrack();
  		Log.i("%s ==> %s, %s, %s, %s", mOldUri, mUri, mInitialized, mPrepared,
  				mVideoSizeKnown);
  		mFromNotification = mInitialized && mUri != null
  				&& mUri.equals(mOldUri);
  		mListener.onOpenStart();
  		if (!mFromNotification)
  			openVideo();
  		else
  			openSuccess();
  		return mInitialized;
  	}
  
  	private void setMediaTrack() {
  	}
  
  	private void openVideo() {
  		if (mUri == null || mPlayer == null)
  			return;
  
  		mPlayer.reset();
  		mInitialized = false;
  		mPrepared = false;
  		mVideoSizeKnown = false;
  
  		try {
  			mPlayer.setScreenOnWhilePlaying(true);
  			mPlayer.setDataSource(PlayerService.this, mUri);
  			// if (mLastAudioTrack != -1)
  			// mPlayer.setInitialAudioTrack(mLastAudioTrack);
  			// if (mLastSubTrackId != -1)
  			// mPlayer.setInitialSubTrack(mLastSubTrackId);
  			if (mSurfaceHolder != null && mSurfaceHolder.getSurface() != null
  					&& mSurfaceHolder.getSurface().isValid())
  				mPlayer.setDisplay(mSurfaceHolder);
  			mPlayer.prepareAsync();
  		} catch (IllegalArgumentException e) {
  			Logger.e("openVideo", e);
  		} catch (IllegalStateException e) {
  			Logger.e("openVideo", e);
  		} catch (IOException e) {
  			Logger.e("openVideo", e);
  		}
  	}
  
  	public Uri getUri() {
  		return mUri;
  	}
  
  	public long getMediaId() {
  		return mMediaId;
  	}
  
  	public int getLastAudioTrack() {
  		return mLastAudioTrack;
  	}
  
  	public String getLastSubTrack() {
  		return mLastSubTrack;
  	}
  
  	public int getLastSubTrackId() {
  		return mLastSubTrackId;
  	}
  
  	public void setVPlayerListener(VPlayerListener listener) {
  		mListener = listener;
  	}
  
  	public void setState(int state) {
  		mCurrentState = state;
  	}
  
  	public boolean needResume() {
  		return mInitialized
  				&& (mCurrentState == STATE_NEED_RESUME || mCurrentState == STATE_PREPARED);
  	}
  
  	public boolean ringingState() {
  		return mInitialized && mCurrentState == STATE_RINGING;
  	}
  
  	public void release() {
  		release(true);
  	}
  
  	private void release(boolean all) {
  		if (mPlayer != null) {
  			if (mListener != null)
  				mListener.onCloseStart();
  			mPlayer.reset();
  			mInitialized = false;
  			mPrepared = false;
  			mVideoSizeKnown = false;
  			if (mListener != null)
  				mListener.onCloseComplete();
  		}
  		if (all) {
  			mListener = null;
  			mUri = null;
  		}
  	}
  
  	public void stop() {
  		if (mInitialized) {
  			mPlayer.pause();
  		}
  	}
  
  	public void start() {
  		if (mInitialized) {
  			mPlayer.start();
  			setState(STATE_PLAYING);
  		}
  	}
  
  	public void setDisplay(SurfaceHolder surface) {
  		mSurfaceHolder = surface;
  		if (mPlayer != null)
  			mPlayer.setDisplay(surface);
  	}
  
  	public void releaseSurface() {
  		if (mInitialized)
  			mPlayer.releaseDisplay();
  	}
  
  	public boolean isPlaying() {
  		return (mInitialized && mPlayer.isPlaying());
  	}
  
  	public int getVideoWidth() {
  		if (mInitialized)
  			return mPlayer.getVideoWidth();
  		return 0;
  	}
  
  	public int getVideoHeight() {
  		if (mInitialized)
  			return mPlayer.getVideoHeight();
  		return 0;
  	}
  
  	public float getVideoAspectRatio() {
  		if (mInitialized)
  			return mPlayer.getVideoAspectRatio();
  		return 0f;
  	}
  
  	public long getDuration() {
  		if (mInitialized)
  			return mPlayer.getDuration();
  		return 0;
  	}
  
  	public long getCurrentPosition() {
  		if (mInitialized)
  			return mPlayer.getCurrentPosition();
  		return 0;
  	}
  
  	public Bitmap getCurrentFrame() {
  		if (mInitialized)
  			return mPlayer.getCurrentFrame();
  		return null;
  	}
  
  	public float getBufferProgress() {
  		if (mInitialized)
  			return mPlayer.getBufferProgress();
  		return 0f;
  	}
  
  	public void seekTo(float percent) {
  		if (mInitialized)
  			mPlayer.seekTo((int) (percent * getDuration()));
  	}
  
  	public String getMetaEncoding() {
  		if (mInitialized)
  			return mPlayer.getMetaEncoding();
  		return null;
  	}
  
  	public void setAudioTrack(int num) {
  		if (mInitialized)
  			mPlayer.selectTrack(num);
  		// mPlayer.setAudioTrack(num);
  	}
  
  	public int getAudioTrack() {
  		if (mInitialized)
  			return mPlayer.getAudioTrack();
  		return 0;
  	}
  
  	// public HashMap<String, Integer> getAudioTrackMap() {
  	// if (!mInitialized)
  	// return null;
  	// String enc = VP.DEFAULT_META_ENCODING;
  	// return mPlayer.getAudioTrackMap(enc.equals(VP.DEFAULT_META_ENCODING) ?
  	// getMetaEncoding() : enc);
  	// }
  	//
  	// public HashMap<String, Object> getSubTrackMap() {
  	// if (!mInitialized)
  	// return null;
  	// String enc = VP.DEFAULT_SUB_ENCODING;
  	// HashMap<String, Object> trackMap = new HashMap<String, Object>();
  	// HashMap<String, Integer> m =
  	// mPlayer.getSubTrackMap(enc.equals(VP.DEFAULT_SUB_ENCODING) ?
  	// getMetaEncoding() : enc);
  	// if (m != null)
  	// for (String k : m.keySet())
  	// trackMap.put(k, m.get(k));
  	//
  	// if (mSubPaths != null)
  	// for (String s : mSubPaths)
  	// trackMap.put(new File(s).getName(), s);
  	//
  	// return trackMap;
  	// }
  	//
  	// public int getSubTrack() {
  	// if (mInitialized)
  	// return mPlayer.getSubTrack();
  	// return 0;
  	// }
  	//
  	// public void setSubTrack(int id) {
  	// if (mInitialized)
  	// mPlayer.setSubTrack(id);
  	// }
  	//
  	// public String getSubPath() {
  	// if (mInitialized)
  	// return mPlayer.getSubPath();
  	// return null;
  	// }
  
  	public void setSubShown(boolean shown) {
  		if (mInitialized)
  			mPlayer.setTimedTextShown(shown);// setSubtitleShown ->
  												// setTimedTextShown 4.0
  	}
  
  	public boolean isBuffering() {
  		return (mInitialized && mPlayer.isBuffering());
  	}
  
  	public void setBuffer(int bufSize) {
  		if (mInitialized)
  			mPlayer.setBufferSize(bufSize);
  	}
  
  	public void setVolume(float left, float right) {
  		if (mInitialized) {
  			if (left <= 0f)
  				left = 0f;
  			else if (left >= 1f)
  				left = 1f;
  			if (right <= 0f)
  				right = 0f;
  			else if (right >= 1f)
  				right = 1f;
  			mPlayer.setVolume(left, right);
  		}
  	}
  
  	public void setVideoQuality(int quality) {
  		if (mInitialized)
  			mPlayer.setVideoQuality(quality);
  	}
  
  	public void setDeinterlace(boolean deinterlace) {
  		if (mInitialized)
  			mPlayer.setDeinterlace(deinterlace);
  	}
  
  	// public int getSubLocation() {
  	// if (mInitialized)
  	// return mPlayer.getSubLocation();
  	// return -1;
  	// }
  	//
  	public void setSubEncoding(String encoding) {
  		if (mInitialized) {
  			String enc = encoding.equals(VP.DEFAULT_SUB_ENCODING) ? null
  					: encoding;
  			mPlayer.setTimedTextEncoding(enc);// setSubEncoding ->
  												// setTimedTextEncoding
  		}
  	}
  
  	public void setSubPath(String subPath) {
  		if (mInitialized)
  			mPlayer.addTimedTextSource(subPath);
  		// mPlayer.setSubPath(subPath);
  	}
  
  	public static interface VPlayerListener {
  		public void onHWRenderFailed();
  
  		public void onVideoSizeChanged(int width, int height);
  
  		public void onSubChanged(String text);
  
  		public void onSubChanged(byte[] pixels, int width, int height);
  
  		public void onOpenStart();
  
  		public void onOpenSuccess();
  
  		public void onOpenFailed();
  
  		public void onBufferStart();
  
  		public void onBufferComplete();
  
  		public void onDownloadRateChanged(int kbPerSec);
  
  		public void onPlaybackComplete();
  
  		public void onCloseStart();
  
  		public void onCloseComplete();
  	}
  
  	private PhoneStateListener mPhoneListener = new PhoneStateListener() {
  		@Override
  		public void onCallStateChanged(int state, String incomingNumber) {
  			switch (state) {
  			case TelephonyManager.CALL_STATE_IDLE:
  				break;
  			case TelephonyManager.CALL_STATE_OFFHOOK:
  			case TelephonyManager.CALL_STATE_RINGING:
  				if (isPlaying()) {
  					stop();
  					setState(STATE_RINGING);
  				}
  				break;
  			default:
  				break;
  			}
  		}
  	};
  
  	private boolean mVideoSizeKnown = false;
  	private boolean mPrepared = false;
  
  	@Override
  	public void onVideoSizeChanged(MediaPlayer arg0, int arg1, int arg2) {
  		mVideoSizeKnown = true;
  		if (mListener != null)
  			mListener.onVideoSizeChanged(arg1, arg2);
  	}
  
  	@Override
  	public void onPrepared(MediaPlayer arg0) {
  		mPrepared = true;
  		openSuccess();
  	}
  
  	private void openSuccess() {
  		mInitialized = true;
  		if (!mFromNotification && mSeekTo > 0 && mSeekTo < 1)
  			seekTo(mSeekTo);
  		mSeekTo = -1;
  		mListener.onOpenSuccess();
  		if (!mFromNotification) {
  			setSubEncoding(VP.DEFAULT_SUB_ENCODING);
  			if (mUri != null)
  				mSubPaths = getSubFiles(mUri.getPath());
  			if (mSubPaths != null)
  				setSubPath(FileUtils.getCanonical(new File(mSubPaths[0])));
  			setSubShown(VP.DEFAULT_SUB_SHOWN);
  		}
  	}
  
  	@Override
  	public void onCompletion(MediaPlayer arg0) {
  		if (mListener != null) {
  			mListener.onPlaybackComplete();
  		} else {
  			release(true);
  		}
  	}
  
  	@Override
  	public void onBufferingUpdate(MediaPlayer arg0, int arg1) {
  	}
  
  	@Override
  	public void onSeekComplete(MediaPlayer arg0) {
  	}
  
  	@Override
  	public boolean onInfo(MediaPlayer arg0, int arg1, int arg2) {
  		switch (arg1) {
  		case MediaPlayer.MEDIA_INFO_BUFFERING_START:
  			if (mListener != null)
  				mListener.onBufferStart();
  			else
  				mPlayer.pause();
  			break;
  		case MediaPlayer.MEDIA_INFO_BUFFERING_END:
  			if (mListener != null)
  				mListener.onBufferComplete();
  			else
  				mPlayer.start();
  			break;
  		case MediaPlayer.MEDIA_INFO_DOWNLOAD_RATE_CHANGED:
  			if (mListener != null)
  				mListener.onDownloadRateChanged(arg2);
  			break;
  		}
  		return true;
  	}
  
  	@Override
  	public boolean onError(MediaPlayer arg0, int arg1, int arg2) {
  		mListener.onOpenFailed();
  		return true;
  	}
  
  	private String[] getSubFiles(String videoPath) {
  		ArrayList<String> files = new ArrayList<String>();
  		for (String ext : MediaPlayer.SUB_TYPES) {
  			File s = new File(videoPath.substring(0,
  					videoPath.lastIndexOf('.') > 0 ? videoPath.lastIndexOf('.')
  							: videoPath.length())
  					+ ext);
  			if (s.exists() && s.isFile() && s.canRead())
  				files.add(s.getAbsolutePath());
  		}
  
  		if (files.isEmpty())
  			return null;
  		else
  			return files.toArray(new String[files.size()]);
  	}
  
  	@Override
  	public void onTimedText(String text) {
  		if (mListener != null)
  			mListener.onSubChanged(text);
  	}
  
  	@Override
  	public void onTimedTextUpdate(byte[] pixels, int width, int height) {
  		if (mListener != null)
  			mListener.onSubChanged(pixels, width, height);
  	}
  
  	// @Override
  	// public void onSubtitleUpdate(String arg0) {
  	// if (mListener != null)
  	// mListener.onSubChanged(arg0);
  	// }
  	//
  	// @Override
  	// public void onSubtitleUpdate(byte[] arg0, int arg1, int arg2) {
  	// if (mListener != null)
  	// mListener.onSubChanged(arg0, arg1, arg2);
  	// }
  
  }
  