getPlayWhenReady with ExoPlayer doesn't work - java

I'm trying to save the current position and current player state of exoplayer
so the current position is work fine when I rotate the screen the video start from where I reach to
but I want to save the state of player so when the player is start and I rotate the screen the player should keep stating and vise verse when the player is paused and I rotate the screen I want the player keep paused too
so this is the code that I tried:
boolean getPlayerWhenReady ;
private long exo_current_position = 0;
private boolean playerStopped = false;
private long playerStopPosition;
private static final String EXO_CURRENT_POSITION = "current_position";
private void initializePlayer(Uri mediaUri) {
if (player == null) {
TrackSelection.Factory videoTrackSelectionFactory = new AdaptiveVideoTrackSelection.Factory(bandwidthMeter);
DefaultTrackSelector trackSelector = new DefaultTrackSelector(handler, videoTrackSelectionFactory);
LoadControl loadControl = new DefaultLoadControl();
player = ExoPlayerFactory.newSimpleInstance(getContext(), trackSelector, loadControl);
exoPlayer.setPlayer(player);
String userAgent = Util.getUserAgent(getContext(), "Baking App");
MediaSource mediaSource = new ExtractorMediaSource(mediaUri, new DefaultDataSourceFactory(getContext(), userAgent), new DefaultExtractorsFactory(), null, null);
player.prepare(mediaSource);
if (exo_current_position != 0 && !playerStopped){
player.seekTo(exo_current_position);
}
else {
player.seekTo(playerStopPosition);
}
player.setPlayWhenReady(getPlayerWhenReady);
}
}
#Override
public void onSaveInstanceState(Bundle currentState) {
super.onSaveInstanceState(currentState);
currentState.putParcelableArrayList("Steps",steps);
currentState.putInt("Step",selectedIndex);
currentState.putLong(EXO_CURRENT_POSITION,player.getCurrentPosition());
getPlayerWhenReady = player.getPlayWhenReady();
currentState.putBoolean("state", getPlayerWhenReady);
}
public boolean isInLandscapeMode( Context context ) {
return (context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE);
}
#Override
public void onDetach() {
super.onDetach();
if (player!=null) {
player.stop();
player.release();
}
}
#Override
public void onDestroyView() {
super.onDestroyView();
if (player!=null) {
player.stop();
player.release();
player=null;
}
}
#Override
public void onStop() {
super.onStop();
if (player!=null) {
player.stop();
playerStopPosition = player.getCurrentPosition();
playerStopped = true;
player.release();
getPlayerWhenReady = player.getPlayWhenReady();
player.setPlayWhenReady(false);
}
}
#Override
public void onPause() {
super.onPause();
if (player!=null) {
player.stop();
player.release();
getPlayerWhenReady = player.getPlayWhenReady();
player.setPlayWhenReady(getPlayerWhenReady);
}
}
#Override
public void onResume() {
super.onResume();
if (player!=null) {
getPlayerWhenReady = player.getPlayWhenReady();
player.setPlayWhenReady(getPlayerWhenReady);
}
}
}
as you can see I use the getPlayWhenReady to save the state of player but it doesn't work when the player is playing and I rotate the screen it paused and when the player is paused and I rotate the screen it just keep paused
thanks I solve the problem by use the:
if(savedInstanceState != null) {
getPlayerWhenReady = savedInstanceState.getBoolean("state");
}

Related

Playing multiple clips the same time android studio - use threads?

Im creating an app in android studio where I want 10 clips to be played at the same time side by side. Im having some problems with some lags already at three clips and I wounder if Im better off using threads? In that case how?
Any hint would be very much apreciated
Here is my code so far. I know it is not very efficient and I am better off using an array of a player object for example but Im just testing so far:
public class MainActivity extends AppCompatActivity implements TextureView.SurfaceTextureListener {
private MediaPlayer mp1, mp2, mp3;
private TextureView tv1, tv2, tv3;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv1 = findViewById(R.id.textureView1);
tv2 = findViewById(R.id.textureView2);
tv3 = findViewById(R.id.textureView3);
tv1.setSurfaceTextureListener(this);
tv2.setSurfaceTextureListener(this);
tv3.setSurfaceTextureListener(this);
}
#Override
public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int width, int height) {
Surface surface = new Surface(surfaceTexture);
mp1 = MediaPlayer.create(this, R.raw.a7);
mp1.setSurface(surface);
// mp1.prepareAsync(); //
mp1.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp1) {
mp1.start();
}
});
Surface surface2 = new Surface(surfaceTexture);
mp2 = MediaPlayer.create(this, R.raw.a9);
mp2.setSurface(surface2);
// mp1.prepareAsync(); //
mp2.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp2) {
mp2.start();
}
});
Surface surface3 = new Surface(surfaceTexture);
mp3 = MediaPlayer.create(this, R.raw.a10);
mp3.setSurface(surface3);
// mp1.prepareAsync(); //
mp3.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp3) {
mp3.start();
}
});
}
#Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
}
#Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
return false;
}
#Override
public void onSurfaceTextureUpdated(SurfaceTexture surface) {
}
#Override
protected void onPause() {
if (mp1 != null && mp1.isPlaying()) {
mp1.pause();
}
super.onPause();
}
#Override
protected void onResume() {
if (mp1 != null) {
mp1.start();
}
super.onResume();
}
#Override
protected void onDestroy() {
if (mp1 != null) {
mp1.stop();
mp1.release();
mp1 = null;
}
super.onDestroy();
}
}
You should play media in a different non-ui thread. like this:-
public class MediaService extends Service {
private MediaPlayer mp1, mp2, mp3;
private static final String ACTION_START = TAG + ".ACTION_START";
private IBinder mBinder = new MyBinder();
private MediaPlayer.OnPreparedListener mMediaPrepared = new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
Log.d(TAG, "MediaPlayer.onPrepared");
onCommandPlay(mp);
}
};
#Override
public IBinder onBind(Intent intent) {
Log.v(TAG, "onBind");
return mBinder;
}
#Override
public void onCreate() {
super.onCreate();
m1 = MediaPlayer.create(this, R.raw.a1);
m2 = MediaPlayer.create(this, R.raw.a2);
m3 = MediaPlayer.create(this, R.raw.a9);
}
#Override
public void onDestroy() {
super.onDestroy();
if (m1 != null) m1 .release();
if (m2 != null) m2 .release();
if (m3 != null) m3 .release();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
final String action = intent.getAction();
Log.d(TAG, "onStartCommand: " + intent.getAction());
if (ACTION_START.equals(action)) {
onCommandStart();
return START_STICKY;
}
stopSelf();
return Service.START_STICKY_COMPATIBILITY;
}
/**
* Performs actions related to media player when Service onStartCommand method is called
*
*/
private void onCommandStart() {
// Create Notifications with remote views
mNotification = new NotificationCompat.Builder(this).setTicker("Media Service started...")
.setSmallIcon(R.mipmap.ic_launcher)
.setContent(collapsed)
.setAutoCancel(false)
.setOngoing(true)
.build();
startForeground(NOTIFICATION_ID, mNotification);
startPlaying();
}
private void onCommandPlay(MediaPlayer mp) {
try {
mp.start();
} catch (IllegalStateException e) {
Log.e(TAG, "onCommandPlay", e);
}
}
/**
* Start playing the provided media item
*
*/
private void startPlaying() {
mCurrent = item;
try {
mp1.reset();
mp1.setOnPreparedListener(mMediaPrepared);
mp2.reset();
mp2.setOnPreparedListener(mMediaPrepared);
mp3.reset();
mp3.setOnPreparedListener(mMediaPrepared);
AssetFileDescriptor afd1 = getResources().openRawResourceFd(getResources().openRawResourceFd(R.raw.a9););
AssetFileDescriptor afd2 = getResources().openRawResourceFd(getResources().openRawResourceFd(R.raw.a10););
AssetFileDescriptor afd3 = getResources().openRawResourceFd(getResources().openRawResourceFd(R.raw.a8););
mp1.setDataSource(afd1 .getFileDescriptor(), afd1 .getStartOffset(), afd1.getLength());
mp2.setDataSource(afd2 .getFileDescriptor(), afd2 .getStartOffset(), afd2 .getLength());
mp3.setDataSource(afd3 .getFileDescriptor(), afd3 .getStartOffset(), afd3 .getLength());
mp1.prepareAsync();
mp2.prepareAsync();
mp3.prepareAsync();
} catch (IOException e) {
Log.e(TAG, "startPlaying", e);
}
}
public class MyBinder extends Binder {
public MediaService getService() {
return MediaService.this;
}
}
}
then start the service from Activity like this:
Intent intent = new Intent(context, MediaService.class);
intent.setAction(ACTION_START);
startServie(intent);
You should also handle different media playing use-cases. You can refer this link for more.

Android Exoplayer save state

Hi I am using ExoPlayer to display video content in my VideoActivity. I am using three variables to save state defined in official docs: playbackPosition,currentWindow, playWhenReady
I am displaying video in full screen when device is in landscape mode so i have 2 layouts one for portrait mode and one for landscape mode:
This is the code for my VideoActivity and I have checked values are properly saved and are properly retrieved:
Video starts from starting when I rotate the device and not from saved position.
public class VideoActivity extends AppCompatActivity {
private SimpleExoPlayerView playerView;
private ExoPlayer player;
private int position;
private ArrayList<RecipeStep> steps;
private boolean playWhenReady;
private int currentWindow;
private long playbackPosition;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_video);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
if(savedInstanceState == null){
playWhenReady = true;
currentWindow = 0;
playbackPosition = 0;
}else {
playWhenReady = savedInstanceState.getBoolean("playWhenReady");
currentWindow = savedInstanceState.getInt("currentWindow");
playbackPosition = savedInstanceState.getLong("playBackPosition");
}
if(getIntent().getExtras() != null) {
position = getIntent().getIntExtra("position", 0);
steps = getIntent().getParcelableArrayListExtra("steps");
}
playerView = findViewById(R.id.video_view);
if(getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT)
setStepTexts(position);
}
private void setStepTexts(int pos){
((TextView) findViewById(R.id.step_short_description)).setText(steps.get(pos-1).getShort_description());
((TextView) findViewById(R.id.step_description)).setText(steps.get(pos-1).getDescription());
}
private void initializePayer(){
player = ExoPlayerFactory.newSimpleInstance(
new DefaultRenderersFactory(this),
new DefaultTrackSelector(), new DefaultLoadControl());
playerView.setPlayer(player);
player.setPlayWhenReady(playWhenReady);
player.seekTo(currentWindow, playbackPosition);
passVideoUri(position);
}
private void passVideoUri(int pos){
Uri uri = Uri.parse(steps.get(pos-1).getVideo_url());
MediaSource mediaSource = buildMediaSource(uri);
player.prepare(mediaSource, true, false);
}
private MediaSource buildMediaSource(Uri uri){
return new ExtractorMediaSource.Factory(
new DefaultHttpDataSourceFactory("exoplayer-codelab")).createMediaSource(uri);
}
#Override
protected void onStart() {
super.onStart();
initializePayer();
}
#Override
protected void onStop() {
super.onStop();
releasePlayer();
}
#Override
protected void onSaveInstanceState(Bundle outState) {
playbackPosition = player.getCurrentPosition();
currentWindow = player.getCurrentWindowIndex();
playWhenReady = player.getPlayWhenReady();
outState.putBoolean("playWhenReady", playWhenReady);
outState.putInt("currentWindow", currentWindow);
outState.putLong("playBackPosition", playbackPosition);
super.onSaveInstanceState(outState);
}
public void previous(View view){
if(position > 1) {
position--;
setStepTexts(position);
passVideoUri(position);
}
}
public void next(View view){
if(position < steps.size()) {
position++;
setStepTexts(position);
passVideoUri(position);
}
}
private void releasePlayer(){
playbackPosition = player.getCurrentPosition();
currentWindow = player.getCurrentWindowIndex();
playWhenReady = player.getPlayWhenReady();
player.release();
player = null;
}
}
Please have a look and see what I am doing wrong.
First you need to prepare the player and then you can seek to desired place. So your code would be like
passVideoUri(position);
playerView.setPlayer(player);
player.setPlayWhenReady(playWhenReady);
player.seekTo(currentWindow, playbackPosition);

My android application is not working with respect to activity life cycle

I'm making flashlight application with handling Activity Life Cycle. The application is running fine but the problem occurs when i call onStop(); while flashlight is on ,when I return from the onStop();, the application should turn on flash light but it doesn't.
I have tried all the methods but the flashOn(); is not enabling the flashlight. I had checked from debugging that the application do nothing if the flashlight was on after returning from onStop();
public class MainActivity extends AppCompatActivity {
private ImageButton imagebtn;
ImageView img;
private Camera camera;
private boolean isFlashOn;
private boolean hasFlash = false;
private Camera.Parameters params;
private boolean flag= false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
imagebtn = (ImageButton) findViewById(R.id.button);
img = findViewById(R.id.torchimage);
isFlashOn = false;
hasFlash = getApplicationContext().getPackageManager()
.hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH);
if (!hasFlash) {
// If device doesn't support flash
// Show alert message and close the application
AlertDialog alert = new AlertDialog.Builder(MainActivity.this)
.create();
alert.setTitle("Error");
alert.setMessage("Sorry, your device doesn't support flash light!");
alert.setButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
finish();//Close application
}
});
alert.show();
}
imagebtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (isFlashOn) {
flashOff();
} else {
flashOn();
}
}
});
}
protected void checkCamera() {
if (camera == null) {
try {
camera = Camera.open();
params = camera.getParameters();
} catch (RuntimeException e) {
Toast.makeText(getApplicationContext(), "Camera not found", Toast.LENGTH_SHORT).show();
}
}
}
**protected void flashOn() {
if (!isFlashOn) {
{
if (camera == null || params == null) {
return;
}
/*if (flag==true) {
flag=false;
params = camera.getParameters();
params.setFlashMode(Parameters.FLASH_MODE_TORCH);
camera.setParameters(params);
camera.startPreview();
*/}
params = camera.getParameters();
params.setFlashMode(Parameters.FLASH_MODE_TORCH);
camera.setParameters(params);
camera.startPreview();
isFlashOn = true;
toggleImages();
btnSound();
}
}**
protected void flashOff() {
if (isFlashOn)
{
if (camera == null || params == null) {
return;
}
params = camera.getParameters();
params.setFlashMode(Parameters.FLASH_MODE_OFF);
camera.setParameters(params);
camera.stopPreview();
isFlashOn = false;
toggleImages();
btnSound();
}
}
protected void btnSound() {
final MediaPlayer mp = MediaPlayer.create(this, R.raw.button_sound);
mp.start();
}
public void toggleImages() {
if (isFlashOn) {
imagebtn.setImageResource(R.drawable.button_on);
img.setImageResource(R.drawable.torch_on);
} else {
imagebtn.setImageResource(R.drawable.button_off);
img.setImageResource(R.drawable.torch_off);
}
}
#Override
protected void onDestroy() {
// Toast.makeText(this,"OnDestroy",Toast.LENGTH_SHORT).show();
super.onDestroy();
}
#Override
protected void onPause() {
super.onPause();
if (isFlashOn)
flashOn();
else
flashOff();
}
#Override
protected void onRestart(){ super.onRestart();
if (isFlashOn==true)
flashOn();
else
flashOff();
}
#Override
protected void onResume() {
super.onResume();
if (isFlashOn == true)
flashOn();
else
flashOff();
}
#Override
protected void onStart() {
super.onStart();
// Toast.makeText(this,"OnStart",Toast.LENGTH_SHORT).show();
// if (hasFlash)
checkCamera();
}
#Override
protected void onStop() {
// Toast.makeText(this, "OnStop", Toast.LENGTH_SHORT).show();
super.onStop();
if (camera != null) {
camera.release();
camera = null;
flag= true;
}
}
Please look again at the Android lifecycle https://developer.android.com/guide/components/activities/activity-lifecycle.html
It goes onStop -> onRestart -> onStart -> onResume
You have an awful lot of crap spread all over the place making what should be easy to see, rather difficult.
So... the flash is on ie isFlashOn = true;
Remove the boolean == true from the if while you're at it. Just if (boolean) works and is much better.
onStop... camera = null; flag= true;
But isFlashOn is still true
Returned to Activity...
onRestart... if (isFlashOn==true) flashOn(); <--- It is, so going to flashOn()
flashOn() {
if (!isFlashOn) { <------------- No the boolean is still true so this isn't run... camera is null anyway.
onStart... checkCamera() {
if (camera == null) { <------ Yes, OK
onResume... if (isFlashOn == true) <----- Again same problem, so camera never starts.
Set isFlashOn = false in onStop
Also remove code from resume or restart... its just duplicated and going through the same thing twice.
Hopefully this teaches you how to debug better. Learn from it.

Android App does not work on run time taking some time to work, how to solve this issue

I am new in android development and learning android apps development. I have created a very basic and simple Flashlight for android device. I am facing the issue when i run the app it takes some time to run like if i press turn on flash light it will take some time (half sec or less but it take some time), i didn't use wait() method in my app. How to run it really fast like user click on it flash turn on or turn off?
public class MainActivity extends AppCompatActivity {
private ImageButton imageButton;
private Camera camera;
private boolean isFlashOn;
private boolean hasFlash;
private Camera.Parameters params;
private MediaPlayer mp;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
imageButton = (ImageButton) findViewById(R.id.switch_btn);
//Check that Device has supports flash or not
hasFlash = getApplicationContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH);
if (!hasFlash){
//If device does not supports Flash
AlertDialog alert = new AlertDialog.Builder(MainActivity.this).create();
alert.setTitle("Error");
alert.setMessage("Sorry, your current device does not support to Little Flashy! ops");
alert.setButton("Ok", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
//Close application
finish();
}
});
alert.show();
return;
}
//Get the Camera
getCamera();
//Display button image
toggleButtonImage();
imageButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (isFlashOn) {
turnOffFlash();
} else
{
turnOnFlash();
}
}
});
}
private void toggleButtonImage() {
if (isFlashOn){
imageButton.setImageResource(R.drawable.btn_switch_on);}
else {imageButton.setImageResource(R.drawable.btn_switch_off);}
}
private void getCamera() {
if (camera == null){
try{
camera = camera.open();
params = camera.getParameters();
}catch (RuntimeException e){
Log.d("Camera Error.", e.getMessage());
}
}
}
/*
* Turning On flash
*/
private void turnOnFlash() {
if (!isFlashOn) {
if (camera == null || params == null) {
return;
}
// play sound
playSound();
params = camera.getParameters();
params.setFlashMode(Parameters.FLASH_MODE_TORCH);
camera.setParameters(params);
camera.startPreview();
isFlashOn = true;
// changing button/switch image
toggleButtonImage();
}
}
/*
* Turning Off flash
*/
private void turnOffFlash() {
if (isFlashOn) {
if (camera == null || params == null) {
return;
}
// play sound
playSound();
params = camera.getParameters();
params.setFlashMode(Parameters.FLASH_MODE_OFF);
camera.setParameters(params);
camera.stopPreview();
isFlashOn = false;
// changing button/switch image
toggleButtonImage();
}
}
private void playSound() {
if (isFlashOn){
mp = MediaPlayer.create(MainActivity.this, R.raw.light_switch_off);}
else {
mp= MediaPlayer.create(MainActivity.this, R.raw.light_switch_on);
}
mp.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mp) {
mp.release();
}
});
mp.start();
}
#Override
protected void onDestroy() {
super.onDestroy();
}
#Override
protected void onPause() {
super.onPause();
//turn off flash when on Pause called
turnOffFlash();
}
#Override
protected void onRestart() {
super.onRestart();
}
#Override
protected void onResume() {
super.onResume();
if (hasFlash) turnOnFlash();
}
#Override
protected void onStart() {
super.onStart();
getCamera();
}
#Override
protected void onStop() {
super.onStop();
if (camera != null){
camera.release();
camera = null;
}
}
}
Before you turn the flash on and off, you call the playSound method, which uses the MediaPlayer. this method is slow and causes your delay. First try to remove it (by commenting it out) and see the difference. Next, you can try to run it from a thread.
Yes, you can ignore the sound feature for current time. Or if you really want this feature than use it through Thread it will show no lag or delay in your app while user turn on or turn off flash.

MediaPlayer continue playing only when specific activity starts

I have a Mediaplayer of background music for my activity. I want to pause it and reset it when new activity starts and stop it when the activity destroys.
I did it like that:
#Override
protected void onResume() {
if(!continiue){
continiue=true;
try{
if (m != null) {
m=new MediaPlayer();
m.reset();
m = MediaPlayer.create(this, R.raw.menu);
m.start();
m.setLooping(true);
}
else{
m.start();
}
}
catch(Exception e){
e.printStackTrace();
}
super.onResume();
}
}
#Override
protected void onStop() {
try{
if(m!=null){
m.stop();
m.release();
}
}
catch(Exception e){
}
super.onStop();
}
#Override
protected void onPause() {
try{
if(m.isPlaying()){
m.pause();
}
}
catch(Exception e){
}
super.onPause();
}
This worked fine. Now I want to add another activity but I want the music to continue playing only when this specific activity opens. How can I do that?
Create a separate class only for music playing and rule it from Activities. Something like this:
import android.content.Context;
import android.content.Intent;
import android.media.MediaPlayer;
import android.util.Log;
public class BackgroundMusicPlayer {
private static MediaPlayer mp = null;
private static int playingResId;
public static boolean isSoundTurnedOff;
private static boolean isPaused;
/** Stop old sound and start new one */
public static void play(Context context, int resIdToPlay) {
if (isSoundTurnedOff || context==null)
return;
if (mp != null && playingResId==resIdToPlay) {
if (isPaused)
mp.start();
isPaused = false;
return;
}
stop();
Intent i = new Intent("com.android.music.musicservicecommand");
i.putExtra("command", "pause");
context.sendBroadcast(i);
playingResId = resIdToPlay;
mp = MediaPlayer.create(context, resIdToPlay);
if (mp != null) {
mp.setLooping(true);
mp.start();
} else
Log.e("BackgroundMusicPlayer","Cant create MediaPlayer. MediaPlayer.create(context: "+context+", resIdToPlay: "+resIdToPlay+") returns null");
}
/** Stop the music */
public static void stop() {
if (mp != null) {
isPaused = false;
playingResId = 0;
mp.stop();
mp.release();
mp = null;
}
}
public static void pause() {
if (mp != null){
mp.pause();
isPaused = true;
}
}
public static void resume() {
if (mp != null && isPaused){
mp.start();
isPaused = false;
}
}
}

Categories

Resources