package android.marshon.likequanmintv.controller;
import android.content.Context;
import android.marshon.likequanmintv.base.APP;
import android.marshon.likequanmintv.librarys.utils.LogUtil;
import android.marshon.likequanmintv.mvp.live.ui.BaseLiveUI;
import android.media.AudioManager;
import android.os.PowerManager;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import com.pili.pldroid.player.AVOptions;
import com.pili.pldroid.player.PLMediaPlayer;
import java.io.IOException;
/**
* Created by ITMarshon.Chen on 2016/11/27.
* emal:itmarshon@163.com
* desc:
*/
public class LivePlayerHolder {
private static final String TAG = LivePlayerHolder.class.getSimpleName();
private Integer codec;
private BaseLiveUI mActivity;
private AVOptions mAVOptions;
public int mSurfaceWidth;
public int mSurfaceHeight;
public SurfaceView mSurfaceView;
public PLMediaPlayer mMediaPlayer;
private String mVideoPath;
private boolean mIsStopped = false;
public LivePlayerHolder(BaseLiveUI mActivity, SurfaceView surfaceView, Integer codec, String mVideoPath){
this.mActivity=mActivity;
this.codec=codec;
this.mVideoPath=mVideoPath;
this.mSurfaceView=surfaceView;
//init
mSurfaceView.getHolder().addCallback(mCallback);
mAVOptions = new AVOptions();
mAVOptions.setInteger(AVOptions.KEY_PREPARE_TIMEOUT, 10 * 1000);
mAVOptions.setInteger(AVOptions.KEY_GET_AV_FRAME_TIMEOUT, 10 * 1000);
mAVOptions.setInteger(AVOptions.KEY_LIVE_STREAMING, 1);
mAVOptions.setInteger(AVOptions.KEY_DELAY_OPTIMIZATION, 1);
mAVOptions.setInteger(AVOptions.KEY_MEDIACODEC, codec);
// whether start play automatically after prepared, default value is 1
mAVOptions.setInteger(AVOptions.KEY_START_ON_PREPARED, 0);
AudioManager audioManager = (AudioManager) APP.getContext().getSystemService(Context.AUDIO_SERVICE);
audioManager.requestAudioFocus(null, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
}
private SurfaceHolder.Callback mCallback = new SurfaceHolder.Callback() {
@Override
public void surfaceCreated(SurfaceHolder holder) {
prepare();
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
mSurfaceWidth = width;
mSurfaceHeight = height;
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
// release();
release();
}
};
private PLMediaPlayer.OnVideoSizeChangedListener mOnVideoSizeChangedListener = new PLMediaPlayer.OnVideoSizeChangedListener() {
public void onVideoSizeChanged(PLMediaPlayer mp, int width, int height) {
Log.i(TAG, "onVideoSizeChanged, width = "+ width + ",height = " + height);
// resize the display window to fit the screen
if (width != 0 && height != 0) {
float ratioW = (float) width/(float) mSurfaceWidth;
float ratioH = (float) height/(float) mSurfaceHeight;
float ratio = Math.max(ratioW, ratioH);
width = (int) Math.ceil((float)width/ratio);
height = (int) Math.ceil((float)height/ratio);
// FrameLayout.LayoutParams layout = new FrameLayout.LayoutParams(width, height);
// layout.gravity = Gravity.CENTER;
// mSurfaceView.setLayoutParams(layout);
}
}
};
private PLMediaPlayer.OnPreparedListener mOnPreparedListener = new PLMediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(PLMediaPlayer mp) {
Log.i(TAG, "On Prepared !");
startPlayer();
mIsStopped = false;
}
};
private PLMediaPlayer.OnInfoListener mOnInfoListener = new PLMediaPlayer.OnInfoListener() {
@Override
public boolean onInfo(PLMediaPlayer mp, int what, int extra) {
Log.i(TAG, "OnInfo, what = " + what + ", extra = " + extra);
switch (what) {
case PLMediaPlayer.MEDIA_INFO_BUFFERING_START:
mActivity.onConnecting();
break;
case PLMediaPlayer.MEDIA_INFO_BUFFERING_END:
case PLMediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START:
mActivity.onConnectSucces();
break;
default:
break;
}
return true;
}
};
private PLMediaPlayer.OnBufferingUpdateListener mOnBufferingUpdateListener = new PLMediaPlayer.OnBufferingUpdateListener() {
@Override
public void onBufferingUpdate(PLMediaPlayer mp, int percent) {
// Log.d(TAG, "onBufferingUpdate: " + percent + "%");
}
};
/**
* Listen the event of playing complete
* For playing local file, it's called when reading the file EOF
* For playing network stream, it's called when the buffered bytes played over
*
* If setLooping(true) is called, the player will restart automatically
* And `onCompletion` will not be called
*
*/
private PLMediaPlayer.OnCompletionListener mOnCompletionListener = new PLMediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(PLMediaPlayer mp) {
Log.d(TAG, "Play Completed !");
showToastTips("Play Completed !");
mActivity.finish(); //// TODO: 2016/11/27 播放完成
}
};
private PLMediaPlayer.OnErrorListener mOnErrorListener = new PLMediaPlayer.OnErrorListener() {
@Override
public boolean onError(PLMediaPlayer mp, int errorCode) {
boolean isNeedReconnect = false;
Log.e(TAG, "Error happened, errorCode = " + errorCode);
switch (errorCode) {
case PLMediaPlayer.ERROR_CODE_INVALID_URI:
showToastTips("Invalid URL !");
break;
case PLMediaPlayer.ERROR_CODE_404_NOT_FOUND:
showToastTips("404 resource not found !");
break;
case PLMediaPlayer.ERROR_CODE_CONNECTION_REFUSED:
showToastTips("Connection refused !");
break;
case PLMediaPlayer.ERROR_CODE_CONNECTION_TIMEOUT:
showToastTips("Connection timeout !");
isNeedReconnect = true;
break;
case PLMediaPlayer.ERROR_CODE_EMPTY_PLAYLIST:
showToastTips("Empty playlist !");
break;
case PLMediaPlayer.ERROR_CODE_STREAM_DISCONNECTED:
showToastTips("Stream disconnected !");
isNeedReconnect = true;
break;
case PLMediaPlayer.ERROR_CODE_IO_ERROR:
showToastTips("Network IO Error !");
isNeedReconnect = true;
break;
case PLMediaPlayer.ERROR_CODE_UNAUTHORIZED:
showToastTips("Unauthorized Error !");
break;
case PLMediaPlayer.ERROR_CODE_PREPARE_TIMEOUT:
showToastTips("Prepare timeout !");
isNeedReconnect = true;
break;
case PLMediaPlayer.ERROR_CODE_READ_FRAME_TIMEOUT:
showToastTips("Read frame timeout !");
isNeedReconnect = true;
break;
case PLMediaPlayer.MEDIA_ERROR_UNKNOWN:
break;
default:
showToastTips("unknown error !");
break;
}
// Todo pls handle the error status here, reconnect or call finish()
release();
if (isNeedReconnect) {
mActivity.onReConnecting();
prepare();
} else {
mActivity.finish();
}
// Return true means the error has been handled
// If return false, then `onCompletion` will be called
return true;
}
};
private void showToastTips(String msg) {
LogUtil.i(TAG+msg);
}
public void prepare() {
if (mMediaPlayer != null) {
mMediaPlayer.setDisplay(mSurfaceView.getHolder());
return;
}
try {
mMediaPlayer = new PLMediaPlayer(mActivity, mAVOptions);
mMediaPlayer.setOnPreparedListener(mOnPreparedListener);
mMediaPlayer.setOnVideoSizeChangedListener(mOnVideoSizeChangedListener);
mMediaPlayer.setOnCompletionListener(mOnCompletionListener);
mMediaPlayer.setOnErrorListener(mOnErrorListener);
mMediaPlayer.setOnInfoListener(mOnInfoListener);
mMediaPlayer.setOnBufferingUpdateListener(mOnBufferingUpdateListener);
// set replay if completed
// mMediaPlayer.setLooping(true);
mMediaPlayer.setWakeMode(mActivity, PowerManager.PARTIAL_WAKE_LOCK);
mMediaPlayer.setDataSource(mVideoPath);
mMediaPlayer.setDisplay(mSurfaceView.getHolder());
mMediaPlayer.prepareAsync();
} catch (UnsatisfiedLinkError e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public void startPlayer(){
if (mIsStopped||mMediaPlayer==null) {
prepare();
} else {
mMediaPlayer.start();
mActivity.onPlayerStart();
}
}
public void pausePlayer(){
if (mMediaPlayer!=null)
mMediaPlayer.pause();
mActivity.onPlayePause();
}
public void stopPlayer(){
if (mMediaPlayer!=null){
mIsStopped = true;
mMediaPlayer.stop();
mMediaPlayer.reset();
}
mMediaPlayer=null;
}
public void releaseWithoutStop() {
if (mMediaPlayer != null) {
mMediaPlayer.setDisplay(null);
}
}
public void onResume() {
mSurfaceView.getHolder().addCallback(mCallback);
startPlayer();
}
public void onPause() {
pausePlayer();
}
public void release() {
if (mMediaPlayer != null) {
mMediaPlayer.stop();
mMediaPlayer.release();
mMediaPlayer = null;
}
if (mSurfaceView.getHolder()!=null){
mSurfaceView.getHolder().removeCallback(mCallback);
}
AudioManager audioManager = (AudioManager) APP.getContext().getSystemService(Context.AUDIO_SERVICE);
audioManager.abandonAudioFocus(null);
}
}