[Android Q&A, Help & Troubleshooting] jujul22:
Hello,

I have source code from an appli running on android 3.2 with a WAMP Server and WowZa Server on my desktop. I have to make it accept the HLS (Http Live Streaming). I saw on the web that the Vitamio Library can do that so i used it. I know that natively, android 3.0+ do it well but i do not succeeded make it work successfully.

The player is successfully displayed but no video starts..

After a reboot of my router (because my server didn't answer), the player crash each time.

Somestimes yes, sometimes no, i have some logs, they are as attachment.

I think a buffer problem...

I think I have to implement this method (at the end of my code) but i know what type in it.

public void onBufferingUpdate(MediaPlayer mPlayer, int percent)

IT WORKS VERY WELL WITH .MP4

Here's my code from the Player Activity :

package fr.niji.broadpeak.activity;

import java.io.File;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
/*import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnBufferingUpdateListener;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnErrorListener;
import android.media.MediaPlayer.OnPreparedListener;
import android.media.MediaPlayer.OnVideoSizeChangedListener;*/
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.OnPreparedListener;
import io.vov.vitamio.MediaPlayer.OnVideoSizeChangedListener;
import io.vov.vitamio.VitamioInstaller;
import io.vov.vitamio.widget.MediaController;
import io.vov.vitamio.widget.VideoView;

import android.os.Bundle;
import android.os.Handler;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
//import io.vov.vitamio.widget.VideoView;
import android.view.View;
import android.view.SurfaceHolder.Callback;
import android.view.View.OnClickListener;
import android.widget.ImageButton;
import android.widget.RelativeLayout;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.SeekBar.OnSeekBarChangeListener;
import fr.niji.broadpeak.R;
import fr.niji.broadpeak.dataproxy.service.BroadpeakDataManager;
import fr.niji.broadpeak.dataproxy.webservice.getsessionurl.GetSessionUrl;
import fr.niji.broadpeak.util.Config;
import fr.niji.broadpeak.util.Resources;
import fr.niji.broadpeak.util.TimeUtils;
import fr.niji.lib.dataproxy.model.ResponseBusinessObject;
import fr.niji.lib.dataproxy.service.DataManager.OnDataListener;
import fr.niji.lib.dataproxy.service.model.BusinessResponse;

public class BroadpeakDemoPlayer extends Activity implements OnClickListener, OnPreparedListener, OnErrorListener,
OnVideoSizeChangedListener, Callback, OnSeekBarChangeListener, OnCompletionListener, OnDataListener, OnBufferingUpdateListener{

private static final String LOG_TAG = BroadpeakDemoPlayer.class.getSimpleName();

public static final String PLAYER_FILE_PATH = "playerLivePath";
public static final String PLAYER_FILE_ID = "playerFileId";
public static final String PLAYER_TYPE = "playerType";
public static final String PLAYER_RESUME_POSITION = "playerResumePosition";
public static final int TYPE_VOD_CONNECTED = 1;
public static final int TYPE_VOD_EMULATED = 2;
public static final int TYPE_LIVE_CONNECTED = 3;
public static final int TYPE_LIVE_EMULATED = 4;

private static final int DELTA_RW_FW = 5000;
private static final int DELTA_LIVE = 30000;

private static final int PROGRESS_BAR_UPDATE_DELAY = 1500;

private SurfaceView mSurfaceView;
//private SurfaceView mSurfaceView;
private SurfaceHolder mSurfaceHolder;
private MediaPlayer mMediaPlayer;
//VitamioInstaller vitamioInstaller;
private int mPlayerType;
private int mCurrentBufferPercentage;
private String mFilePath;
private String mFileId;
private int mResumePosition;
int percentBuffer;

private Toast mToast;
private WakeLock mWakeLock;

private int mTerminalType;
private String mUserId;
private long mLastPosition;

private RelativeLayout mLayoutControls;
private boolean mIsLayoutControlsVisible = true;
private SeekBar mSeekBar;
private TextView mTextViewCurrentTime;
private TextView mTextViewFullTime;
private ImageButton mButtonStartOver;
private ImageButton mButtonPlay;
private ImageButton mButtonPause;
private ImageButton mButtonRewind;
private ImageButton mButtonForward;
private ImageButton mButtonLive;
private boolean mIsButtonLiveEnabled = true;

private boolean mIsVideoReadyToBePlayed = false;
private boolean mIsVideoDimensionsKnown = false;
private int mVideoHeight = 0;
private int mVideoWidth = 0;
private long mVideoLength = -1;
private int mRequestId = -1;

private Runnable mRunnableProgressBarUpdate;
private Handler mHandler = new Handler();

private BroadpeakDataManager mDataManager;
private String mErrorGettingVideo;
private String mErrorPlayingVideo;

@Override
public void onCreate(final Bundle bundle) {
super.onCreate(bundle);

Intent intent = getIntent();
mDataManager = BroadpeakDataManager.getInstance(this);
mErrorGettingVideo = getString(R.string.error_getting_video_url);
mErrorPlayingVideo = getString(R.string.error_playing_video);

if (intent != null) {
mPlayerType = intent.getIntExtra(PLAYER_TYPE, 0);

mFilePath = intent.getStringExtra(PLAYER_FILE_PATH);
mFileId = intent.getStringExtra(PLAYER_FILE_ID);
if (Config.SHOW_LOG) {
Log.d(LOG_TAG, "mFilePath: " + mFilePath);
Log.d(LOG_TAG, "mFileId: " + mFileId);
}
mResumePosition = intent.getIntExtra(PLAYER_RESUME_POSITION, 0);
// must retrieve url ?
if (mFilePath == null || mFilePath.length() == 0) {
try {
mRequestId = mDataManager.getSessionUrl(this, mFileId, Resources.getInstance().mUserId);
mDataManager.addOnDataListener(mRequestId, this);
} catch (final UnsupportedEncodingException e) {
e.printStackTrace();
}
}
}

setContentView(R.layout.player);

// Decalage a 30s pour le live emulated
if (mPlayerType == TYPE_LIVE_EMULATED) {
mResumePosition = Config.LIVE_DEFAULT_OFFSET;
}

// Player management
//mSurfaceView = (SurfaceView) findViewById(R.id.surface_live);
mSurfaceView = (SurfaceView) findViewById(R.id.surface_live);
mSurfaceView.setOnClickListener(this);
mSurfaceHolder = mSurfaceView.getHolder();
mSurfaceHolder.addCallback(this);
mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

// Controls management
mLayoutControls = (RelativeLayout) findViewById(R.id.player_controls);
mLayoutControls.setClickable(true);

mSeekBar = (SeekBar) findViewById(R.id.seek_bar);
mSeekBar.setOnSeekBarChangeListener(this);
mTextViewCurrentTime = (TextView) findViewById(R.id.textview_current_time);
mTextViewFullTime = (TextView) findViewById(R.id.textview_full_time);

mButtonStartOver = (ImageButton) findViewById(R.id.btn_startover);
mButtonStartOver.setOnClickListener(this);

mButtonPlay = (ImageButton) findViewById(R.id.btn_play);
mButtonPlay.setOnClickListener(this);

mButtonPause = (ImageButton) findViewById(R.id.btn_pause);
mButtonPause.setOnClickListener(this);

mButtonRewind = (ImageButton) findViewById(R.id.btn_rw);
mButtonRewind.setOnClickListener(this);

mButtonForward = (ImageButton) findViewById(R.id.btn_fw);
mButtonForward.setOnClickListener(this);

mButtonLive = (ImageButton) findViewById(R.id.btn_live);
mButtonLive.setOnClickListener(this);

Resources resources = Resources.getInstance();
mTerminalType = resources.mTerminalType;
mUserId = resources.mUserId;

// Player type management
switch (mPlayerType) {
case TYPE_LIVE_CONNECTED:
mLayoutControls.setVisibility(View.GONE);
mIsLayoutControlsVisible = false;
break;
case TYPE_LIVE_EMULATED:
mSeekBar.setVisibility(View.GONE);
mTextViewCurrentTime.setVisibility(View.GONE);
mTextViewFullTime.setVisibility(View.GONE);
break;
case TYPE_VOD_CONNECTED:
mButtonStartOver.setVisibility(View.GONE);
mButtonLive.setVisibility(View.GONE);
break;
case TYPE_VOD_EMULATED:
mButtonStartOver.setVisibility(View.GONE);
mButtonLive.setVisibility(View.GONE);
break;
}

mRunnableProgressBarUpdate = new Runnable() {
public void run() {
mHandler.removeCallbacks(mRunnableProgressBarUpdate);
int progress = -1;
if (mMediaPlayer != null && mMediaPlayer.isPlaying()) {
if (mVideoLength > 0) {
final long currentPosition = mMediaPlayer.getCurrentPosition();
progress = (int) Math.floor(currentPosition / (float) mVideoLength * 100);
mSeekBar.setProgress(progress);
mTextViewCurrentTime.setText(TimeUtils.formatDuration(currentPosition / 1000));
} else {
progress = 0;
mSeekBar.setProgress(progress);
mTextViewCurrentTime.setText("");
}
}

mHandler.postDelayed(mRunnableProgressBarUpdate, PROGRESS_BAR_UPDATE_DELAY);
}
};
}

@Override
protected void onResume() {
super.onResume();
acquireWakeLock();
}

@Override
protected void onPause() {
super.onPause();
releaseMediaPlayer();
doCleanUp();
releaseWakeLock();
}

@Override
protected void onStop() {
super.onStop();
if (mPlayerType == TYPE_VOD_CONNECTED) {
try {
BroadpeakDataManager.getInstance(this).retrieveSetLastPlay(BroadpeakDataManager.TYPE_NETWORK, null,
mTerminalType, mUserId, mFileId, mLastPosition, -1);
} catch (UnsupportedEncodingException e) {
Log.e(LOG_TAG, "Error while calling setLastPlay", e);
}
}
}

@Override
protected void onDestroy() {
super.onDestroy();
releaseMediaPlayer();
doCleanUp();
}

public void surfaceChanged(final SurfaceHolder holder, final int format, final int width, final int height) {
Log.d(LOG_TAG, "surfaceChanged called");
}

public void surfaceDestroyed(final SurfaceHolder holder) {
Log.d(LOG_TAG, "surfaceDestroyed called");

}

public void surfaceCreated(final SurfaceHolder holder) {
Log.d(LOG_TAG, "surfaceCreated called");
if (mFilePath != null) {
playVideo();
}

}

public void onClick(final View view) {
if (view == mSurfaceView) {
if (mPlayerType != TYPE_LIVE_CONNECTED) {
mLayoutControls.setVisibility(mIsLayoutControlsVisible ? View.GONE : View.VISIBLE);
mIsLayoutControlsVisible = !mIsLayoutControlsVisible;
}
} else if (view == mButtonPlay) {
pressPlayButton();
} else if (view == mButtonPause) {
pressPauseButton();
} else if (view == mButtonRewind) {
if (mPlayerType == TYPE_LIVE_CONNECTED || mPlayerType == TYPE_LIVE_EMULATED) {
mButtonLive.setEnabled(true);
mButtonForward.setEnabled(true);
mIsButtonLiveEnabled = true;
}

try {
if (mMediaPlayer != null && mMediaPlayer.isPlaying()) {
mMediaPlayer.seekTo(mMediaPlayer.getCurrentPosition() - DELTA_RW_FW);
}
} catch (Exception e) {
Log.e(LOG_TAG, "An error occurred", e);
}
} else if (view == mButtonForward) {
if (mPlayerType == TYPE_LIVE_CONNECTED || mPlayerType == TYPE_LIVE_EMULATED) {
mButtonStartOver.setEnabled(true);
}

try {
if (mMediaPlayer != null && mMediaPlayer.isPlaying()) {
mMediaPlayer.seekTo(mMediaPlayer.getCurrentPosition() + DELTA_RW_FW);
}
} catch (Exception e) {
Log.e(LOG_TAG, "An error occurred", e);
}
} else if (view == mButtonLive) {
mButtonForward.setEnabled(false);
mButtonLive.setEnabled(false);
mIsButtonLiveEnabled = false;

mButtonStartOver.setEnabled(true);

try {
if (mMediaPlayer != null && mMediaPlayer.isPlaying()) {
mMediaPlayer.seekTo(mMediaPlayer.getCurrentPosition() + DELTA_LIVE);
}
} catch (Exception e) {
Log.e(LOG_TAG, "An error occurred", e);
}

} else if (view == mButtonStartOver) {
mButtonLive.setEnabled(true);
mButtonForward.setEnabled(true);
mIsButtonLiveEnabled = true;

try {
if (mMediaPlayer != null && mMediaPlayer.isPlaying()) {
mMediaPlayer.seekTo(0);
}
} catch (Exception e) {
Log.e(LOG_TAG, "An error occurred", e);
}
}
}

private void pressPauseButton() {
mButtonPlay.setVisibility(View.VISIBLE);
mButtonPause.setVisibility(View.GONE);
mButtonForward.setEnabled(false);
mButtonRewind.setEnabled(false);

if (mPlayerType == TYPE_LIVE_CONNECTED || mPlayerType == TYPE_LIVE_EMULATED) {
mButtonLive.setEnabled(false);
mButtonStartOver.setEnabled(false);
}

try {
if (mMediaPlayer != null && mMediaPlayer.isPlaying()) {
mMediaPlayer.pause();
}
} catch (Exception e) {
Log.e(LOG_TAG, "An error occurred", e);
}
}

private void pressPlayButton() {
mButtonPlay.setVisibility(View.GONE);
mButtonPause.setVisibility(View.VISIBLE);

if (mPlayerType == TYPE_LIVE_CONNECTED || mPlayerType == TYPE_LIVE_EMULATED) {
if (mIsButtonLiveEnabled) {
mButtonLive.setEnabled(true);
mButtonForward.setEnabled(true);
}
mButtonRewind.setEnabled(true);
mButtonStartOver.setEnabled(true);
} else {
mButtonRewind.setEnabled(true);
mButtonForward.setEnabled(true);
}

try {
if (mMediaPlayer != null && !mMediaPlayer.isPlaying()) {
mMediaPlayer.start();
}
} catch (Exception e) {
Log.e(LOG_TAG, "An error occurred", e);
}
}

private void playVideo() {
doCleanUp();
try {
// Create a new media player and set the listeners
/*mMediaPlayer = new MediaPlayer();
mMediaPlayer.setDataSource(mFilePath);
mMediaPlayer.setLooping(mPlayerType == TYPE_LIVE_CONNECTED || mPlayerType == TYPE_LIVE_EMULATED);
mMediaPlayer.setDisplay(mSurfaceHolder);
mMediaPlayer.prepare();
mMediaPlayer.seekTo(mResumePosition);
mMediaPlayer.setOnPreparedListener(this);
mMediaPlayer.setOnVideoSizeChangedListener(this);
mMediaPlayer.setOnCompletionListener(this);
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);*/

mMediaPlayer = new MediaPlayer(this);
mMediaPlayer.setDataSource(mFilePath);
mMediaPlayer.setDisplay(mSurfaceHolder);
mMediaPlayer.prepare();
mMediaPlayer.seekTo(mResumePosition);
mMediaPlayer.setScreenOnWhilePlaying(true);
mMediaPlayer.setOnBufferingUpdateListener(this);
mMediaPlayer.setOnCompletionListener(this);
//mMediaPlayer.setAudioTrack(AudioManager.STREAM_MUSIC);
mMediaPlayer.setOnPreparedListener(this);
mMediaPlayer.setOnVideoSizeChangedListener(this);

} catch (Exception e) {
Log.e(LOG_TAG, "error: " + e.getMessage(), e);
showErrorMessage(mErrorPlayingVideo);
// Toast.makeText(this, "Impossible de jouer la vidÃ©o",
// 5000).show();
}
}

private void releaseMediaPlayer() {
if (mMediaPlayer != null) {
mLastPosition = mMediaPlayer.getCurrentPosition() / 1000;
mMediaPlayer.release();
mMediaPlayer = null;
}
}

private void doCleanUp() {
mVideoWidth = 0;
mVideoHeight = 0;
mVideoLength = -1;
mIsVideoReadyToBePlayed = false;
mIsVideoDimensionsKnown = false;
mHandler.removeCallbacks(mRunnableProgressBarUpdate);
}

private void acquireWakeLock() {
PowerManager.WakeLock wl = mWakeLock;
if (wl == null) {
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
wl = mWakeLock = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE, LOG_TAG);
}
if (!wl.isHeld()) {
wl.acquire();
Log.d(LOG_TAG, "acquire wakelock");
}
}

private void releaseWakeLock() {
PowerManager.WakeLock wl = mWakeLock;
if (wl != null) {
if (wl.isHeld()) {
wl.release();
Log.d(LOG_TAG, "release wakelock");
}
}
}

private void showErrorMessage(final String string) {
if (mToast != null) {
mToast.cancel();
mToast.setText(string);
} else {
mToast = Toast.makeText(this, string, Toast.LENGTH_LONG);
}
mToast.show();
}

private void startVideoPlayback() {
Log.d(LOG_TAG, "startReading: width " + mVideoWidth + " height " + mVideoHeight);
mSurfaceHolder.setFixedSize(mVideoWidth, mVideoHeight);

mVideoLength = mMediaPlayer.getDuration();
mTextViewFullTime.setText(TimeUtils.formatDuration(mVideoLength / 1000));

mMediaPlayer.start();
if (mPlayerType == TYPE_VOD_CONNECTED || mPlayerType == TYPE_VOD_EMULATED) {
mHandler.post(mRunnableProgressBarUpdate);
}
}

public void onPrepared(final MediaPlayer mediaPlayer) {
Log.d(LOG_TAG, "onPrepared");
mIsVideoReadyToBePlayed = true;
if (mIsVideoReadyToBePlayed && mIsVideoDimensionsKnown) {
startVideoPlayback();
}
}

public void onVideoSizeChanged(final MediaPlayer mediaPlayer, final int width, final int height) {
Log.d(LOG_TAG, "OnVideoSizeChanged");

if (width > 0 && height > 0) {
mVideoHeight = height;
mVideoWidth = width;
mIsVideoDimensionsKnown = true;
if (mIsVideoReadyToBePlayed && mIsVideoDimensionsKnown) {
startVideoPlayback();
}
}
}

public boolean onError(final MediaPlayer mediaPlayer, final int what, final int extra) {
doCleanUp();
showErrorMessage("An error occurred");
return false;
}

public void onProgressChanged(final SeekBar seekBar, final int progress, final boolean fromUser) {
if (fromUser) {
if (mVideoLength > 0) {
final int currentPosition = ((int) Math.floor(progress / 100f * mVideoLength)) / 1000;
mTextViewCurrentTime.setText(TimeUtils.formatDuration(currentPosition));
} else {
mTextViewCurrentTime.setText("");
}
}
}

public void onStartTrackingTouch(final SeekBar seekBar) {
if (mPlayerType == TYPE_VOD_CONNECTED || mPlayerType == TYPE_VOD_EMULATED) {
mHandler.removeCallbacks(mRunnableProgressBarUpdate);
}

pressPauseButton();
}

public void onStopTrackingTouch(final SeekBar seekBar) {
if (mPlayerType == TYPE_VOD_CONNECTED || mPlayerType == TYPE_VOD_EMULATED) {
mHandler.post(mRunnableProgressBarUpdate);
}

final int currentPosition = (int) Math.floor(mSeekBar.getProgress() / 100f * mVideoLength);

try {
if (mMediaPlayer != null) {
mMediaPlayer.seekTo(currentPosition);
}
} catch (Exception e) {
Log.e(LOG_TAG, "An error occurred", e);
}

pressPlayButton();
}

public void onCompletion(final MediaPlayer mediaPlayer) {
mMediaPlayer.seekTo(0);
mSeekBar.setProgress(0);

mTextViewCurrentTime.setText(TimeUtils.formatDuration(0));

mButtonPlay.setVisibility(View.VISIBLE);
mButtonPause.setVisibility(View.GONE);
}

public void onCacheRequestFinished(ResponseBusinessObject response) {

}

public void onDataFromDatabase(int code, ArrayList<?> data) {

}

public void onRequestFinished(int requestId, boolean suceed, BusinessResponse response) {
if (Config.SHOW_LOG) {
Log.d(LOG_TAG, "onRequestFinished: " + requestId);
}
try {
if (requestId == mRequestId) {
mDataManager.removeOnDataListener(mRequestId, this);
mRequestId = -1;
final GetSessionUrl urlResponse = (GetSessionUrl) response.response;
mFilePath = urlResponse.mSessionUrl;
if (Config.SHOW_LOG) {
Log.d(LOG_TAG, "onRequestFinished, mFilePath: " + mFilePath);
}
if (mFilePath != null) {
playVideo();
} else {
showErrorMessage(mErrorGettingVideo);
}
}
} catch (Exception e) {
Log.e(LOG_TAG, "onRequestFinished", e);
}

}

@Override
public void onBufferingUpdate(MediaPlayer mPlayer, int percent) {
// TODO Auto-generated method stub

}
}

Commented lines are the lines when i had still not used Vitamio.

Please help me to implement, modify this code to make it works !

Regards,

Julian.