I am stuck with a weird problem. I have an activity with a MediaPlayer that should play a just recorded audio file. At first the mediaplayer is initialized ok and the file can be played.
When I rotate the screen, the activity is destroyed and then reinitialized for the new orientation. Therefore, I re-initialize the mediaplayer too.
this works a couple of times, but at some point mediaPlayer.setDataSource() throws a NullPointerException because the file is suddenly gone. Sadly, I haven't seen any other error in the logs.
Here are some Code snippets:
player creation:
/**
* Creates and initializes the player with the proper file.
*/
private void createPlayer() {
synchronized (playerMutex) {
player = new MediaPlayer();
player.setLooping(false);
player.setOnPreparedListener(this);
player.setOnErrorListener(this);
player.setOnCompletionListener(this);
}
readGreeting();
}
player initialization:
isPrepared = false;
try {
final File file = new File(audioFilename);
in = new FileInputStream(file);
synchronized (playerMutex) {
player.setDataSource(in.getFD());
}
// using a runnable instead of prepareAsync to not accidentally call pause on media player while preparing
Runnable preparer = new Runnable() {
#Override
public void run() {
try {
synchronized (playerMutex) {
if (player != null) {
player.prepare();
}
}
} catch (Exception ex) {
Log.e(TAG, "Error preparing player for file " + file.getAbsolutePath(), ex);
}
}
};
new Thread(preparer).start();
} catch (Exception ex) {
btnPlayback.setEnabled(false);
Log.e(TAG, "Error preparing player", ex);
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
Log.e(TAG, "initPlayer: ", e);
}
}
}
saving instance state...
#Override
protected void onPause() {
synchronized (playerMutex) {
if (isPlaying()) {
getIntent().putExtra(EXTRA_KEY_SEEK, player.getCurrentPosition());
pause();
}
}
setAudioModeBackToNormal();
super.onPause();
}
private void pause() {
synchronized (playerMutex) {
if (isPlaying()) {
player.pause();
}
}
btnPlayback.setVisibility(View.VISIBLE);
btnPause.setVisibility(View.GONE);
}
#Override
protected void onSaveInstanceState(Bundle outState) {
final Bundle extras = getIntent().getExtras();
outState.putBundle("extras", extras);
super.onSaveInstanceState(outState);
}
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
getIntent().putExtras(savedInstanceState.getBundle("extras"));
}
cleanup:
private void stopPlayerAndFreeResources() {
synchronized (playerMutex) {
isPrepared = false;
if (player != null) {
player.stop();
player.release();
player = null;
}
}
if (in != null) {
try {
in.close();
in = null;
} catch (IOException e) {
Log.e(TAG, "Unexpected error", e);
}
}
}
Maybe I'm looking at the problem from the wrong angle and it has nothing to do with player. Has anybody ever had issues with disappearing files?
I had playlist files disappear once. The cause of the problem turned out to be certain media players that had an option to manage my playlists. In this case manage meant deleting the playlists I already had :(
Related
I have a server with a number of audio files which from time to time more files are added. I want those files to be loaded in my android app so they an be played. How would I go about doing this?
I am using native android
Simple AudioHandler class to play, pause, resume audio etc
public class AudioHandler {
private SimpleExoPlayer simpleExoPlayer;
//Start Playing
public void playAudio(String URL) {
try {
if(simpleExoPlayer == null) {
simpleExoPlayer = ExoPlayerFactory.newSimpleInstance(
new DefaultRenderersFactory(mContext),
new DefaultTrackSelector(),
new DefaultLoadControl());
}
// Preparing from url
Uri uri = Uri.parse(URL);
MediaSource mediaSource = buildMediaSource(uri);
simpleExoPlayer.prepare(mediaSource, true, false);
simpleExoPlayer.setPlayWhenReady(true);
simpleExoPlayer.addListener(new Player.DefaultEventListener() {
#Override
public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
super.onPlayerStateChanged(playWhenReady, playbackState);
switch(playbackState) {
case Player.STATE_READY:
// Update UI -- Audio has start playing
break;
case Player.STATE_ENDED:
ReleaseMediaPlayer();
// Update UI -- Audio has ended
break;
default:
break;
}
}
#Override
public void onPlayerError(ExoPlaybackException error) {
super.onPlayerError(error);
ReleaseMediaPlayer();
// Update UI -- error
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
public void pauseAudio(){
try{
if (simpleExoPlayer != null) {
simpleExoPlayer.setPlayWhenReady(false);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void resumeAudioa(){
try{
if (simpleExoPlayer != null) {
simpleExoPlayer.setPlayWhenReady(true);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void ReleaseMediaPlayer(){
try{
if (simpleExoPlayer != null) {
simpleExoPlayer.release();
simpleExoPlayer = null;
}
} catch (Exception e) {
e.printStackTrace();
}
}
private MediaSource buildMediaSource(Uri uri) {
return new ExtractorMediaSource.Factory(
new DefaultHttpDataSourceFactory("exoplayer-audios")).
createMediaSource(uri);
}
// Constructor and other methods...
}
in my simple player i have play, and stop buttons and play and pause media player work fine, now after click on stop and play again, media player don't work and i'm not sure whats problem to resolve that
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
...
playMonthLesson();
...
}
#SuppressLint("DefaultLocale")
public void playMonthLesson() {
try {
mediaPlayer.reset();
mediaPlayer.setDataSource(CoreApplication.MEDIAFOLDER + "/" + lesson.getFilename());
mediaPlayer.prepare();
mediaPlayer.start();
lesson_play.setImageResource(R.drawable.ic_pause);
int totalDuration = mediaPlayer.getDuration();
// set Progress bar values
lesson_progress_bar.setProgress(curretLessonProgress);
lesson_progress_bar.setMax(100);
// Updating progress bar
updateProgressBar();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
#OnClick(R.id.lesson_play)
public void lesson_play(View view) {
if (mediaPlayer == null) {
playMonthLesson();
} else if (mediaPlayer.isPlaying()) {
if (mediaPlayer != null) {
mediaPlayer.pause();
// Changing button image to play button
lesson_play.setImageResource(R.drawable.ic_play);
}
} else {
// Resume song
if (mediaPlayer != null) {
mediaPlayer.start();
// Changing button image to pause button
lesson_play.setImageResource(R.drawable.ic_pause);
}
}
}
#OnClick(R.id.lesson_stop)
public void setLesson_stop(View view) {
if (mediaPlayer != null) {
mediaPlayer.stop();
lesson_play.setImageResource(R.drawable.ic_play);
lesson_progress_bar.setProgress(0);
}
}
According to the MediaPlayer life cycle, which you can view in the Android API guide, I think that you have to call reset() instead of stop(), and after that prepare again the media player (use only one) to play the sound from the beginning. Take also into account that the sound may have finished. So I would also recommend to implement setOnCompletionListener() to make sure that if you try to play again the sound it doesn't fail.
The problem is that when you stop mediaplayer and click on play again your call will go to mediaplayer.play() as mediaplayer is not null.
You will have to null the mediaPlayer on stop method. Now, once you stop mediaplayer and again click on play it will call playMonthLesson();
#OnClick(R.id.lesson_stop)
public void setLesson_stop(View view) {
if (mediaPlayer != null) {
mediaPlayer.stop();
mediaPlayer.reset();
mediaPlayer = null;
lesson_play.setImageResource(R.drawable.ic_play);
lesson_progress_bar.setProgress(0);
}
}
change this code too,
#SuppressLint("DefaultLocale")
public void playMonthLesson() {
try {
mediaPlayer = new MediaPlayer();
mediaPlayer.reset();
mediaPlayer.setDataSource(CoreApplication.MEDIAFOLDER + "/" + lesson.getFilename());
mediaPlayer.setOnPreparedListener(new OnPreparedListener(){
#Override
public void onPrepared(MediaPlayer mp) {
mp.start();
lesson_play.setImageResource(R.drawable.ic_pause);
int totalDuration = mediaPlayer.getDuration();
}
});
mediaPlayer.prepareAsync();
// set Progress bar values
lesson_progress_bar.setProgress(curretLessonProgress);
lesson_progress_bar.setMax(100);
// Updating progress bar
updateProgressBar();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
I'm working in a music player that download a File from firebase and init media player with this LOCALFILE. I've trying to STREAM_AUDIO with Media Player, but couldn't make pause() work properly with online streaming. Now,
pause/player button only call start() and doesn't pause(); stop() reinit audio immediately. How do I fix that?
Public class PerformanceActivity extends Activity {
private ImageButton playerPerf, stopPerf;
protected MediaPlayer mMediaPlayer;
protected ProgressDialog progressDialog;
private static String url = "https://firebasestorage.go....";
private File ARQUIVO_AUDIO;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_perfomance2);
playerPerf = findViewById(R.id.perfPlayId);
stopPerf = findViewById(R.id.perfStopId);
try {
executarProgressDialog();
FirebaseStorage storage = FirebaseStorage.getInstance();
// Create a storage reference from our app
StorageReference storageRef = storage.getReferenceFromUrl(url);
final File localFile = File.createTempFile("audios", ".mp3");
Log.e("MEDIAPLAYER", "localfile criado com sucesso");
storageRef.getFile(localFile).addOnSuccessListener(new OnSuccessListener<FileDownloadTask.TaskSnapshot>() {
#Override
public void onSuccess(FileDownloadTask.TaskSnapshot taskSnapshot) {
try {
mMediaPlayer = new MediaPlayer();
mMediaPlayer.setDataSource(localFile.toString());
Log.e("MEDIAPLAYER","Media player instanciado");
mMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
}
});
mMediaPlayer.prepareAsync();
} catch (IOException e) {
Log.e("MEDIAPLAYER",e.toString());
}
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Toast.makeText(PerfomanceActivity2.this, "ooops falha no download", Toast.LENGTH_LONG).show();
// progressDialog.dismiss();
Log.e("MEDIAPLAYER ERROR", e.toString());
}
});
} catch (IOException e) {
e.printStackTrace();
}
progressDialog.dismiss();
// Botao play/pause que executa o streaming
playerPerf.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (mMediaPlayer!=null) {
if (mMediaPlayer.isPlaying()) {
mMediaPlayer.pause();
Log.e("MEDIAPLAYER", "metodo pause chamado");
}
if (!mMediaPlayer.isPlaying()) {
mMediaPlayer.start();
Log.e("MEDIAPLAYER", "start chamado");
}
}
}
});
// Pause o STREAMING e reinicializa o MediaPlayer
stopPerf.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
try {
if (mMediaPlayer != null) {
mMediaPlayer.stop();
mMediaPlayer.prepare();
}
} catch (Exception e) {
Log.e("Audio erro", e.toString());
}
}
});
}
//libera espaço da memória quando a Activity é destruida
#Override
public void onDestroy() {
if (mMediaPlayer != null) {
mMediaPlayer.stop();
mMediaPlayer.release();
mMediaPlayer = null;
if (progressDialog != null) {
progressDialog.cancel();
}
}
super.onDestroy();
}
//Metodo que executa um ProgressDialog durante o download do audio
void executarProgressDialog() {
try {
progressDialog = new ProgressDialog(PerfomanceActivity2.this);
progressDialog.setMessage("Moluscos trabalhando...");
progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
progressDialog.setTitle("Preparando meditação");
progressDialog.setCancelable(false);
progressDialog.show();
} catch (Exception e) {
Log.e("ProgressDialog Error", "Erro ao inicializar ProgressDialog");
}
}
}
There is an obvious logic problem in playerPerf.OnClickListener.
if (mMediaPlayer!=null) {
if (mMediaPlayer.isPlaying()) {
mMediaPlayer.pause();
Log.e("MEDIAPLAYER", "metodo pause chamado");
}
if (!mMediaPlayer.isPlaying()) { // <= always true because you pause it if not.
mMediaPlayer.start();
Log.e("MEDIAPLAYER", "start chamado");
}
}
The state mMediaPlayer.isPlaying wasn't separate correctly, which caused => if isPlaying then pauses it, directly considering if !isPlaying is always paused. So it always starts it no matter whether it was playing or not.
=> To solve it:
Just add a else instead of considering mMediaPlayer.isPlaying() twice.
if (mMediaPlayer!=null) {
if (mMediaPlayer.isPlaying()) {
mMediaPlayer.pause();
Log.e("MEDIAPLAYER", "metodo pause chamado");
} else { //<= change it to else
//if (!mMediaPlayer.isPlaying()) { // <= remove the second if
mMediaPlayer.start();
Log.e("MEDIAPLAYER", "start chamado");
}
}
My media player for some reason completes while it is paused. Now i have seen another post that said about it being async and 300ms difference and that I understand. But my main problem is that i have 20 seconds left on the video and while paused it finishes after the 20 seconds run out.
here is the relevant code that I might have messed up on:
private void initPlayer()
{
try {
if(videoFile != null)
{
afd = getAssets().openFd(videoFile);
instructionVideoPlayer = new MediaPlayer();
instructionVideoPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getDeclaredLength());
instructionVideoPlayer.setDisplay(holder);
instructionVideoPlayer.prepare();
Log.i("Instruction Video", "videoPrepared");
instructionVideoPlayer.setOnCompletionListener(instructionVideoComplete);
instructionVideoPlayer.setOnPreparedListener(this);
}
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
Log.i(this.toString(), "IOEXception");
e.printStackTrace();
//initPlayer();
} catch (Exception e)
{
Log.i("InitPlayer", e.getClass().toString());
e.printStackTrace();
}
restoreOverlayState();
}
The listeners:
MediaPlayer.OnCompletionListener instructionVideoComplete = new MediaPlayer.OnCompletionListener() {
public void onCompletion(MediaPlayer arg0) {
Log.i("onCompletion", "called");
if(!videoFile.contentEquals(LangSelect.INSTRUCTION_05))
{
Intent returnIntent = new Intent();
returnIntent.putExtra(LangSelect.ACTION, LangSelect.GO_VIDEO_NEXT);
setResult(RESULT_OK, returnIntent);
continuePlaying = true;
toFinish();
}
else
toFinish();
}
};
public void onPrepared(MediaPlayer mediaPlayer)
{
playVideo();
}
the play and pause functions
private void playVideo()
{
instructionVideoPlayer.seekTo(pausedAt);
instructionVideoPlayer.start();
restoreOverlayState();
}
private void pauseVideo()
{
pausedAt = instructionVideoPlayer.getCurrentPosition();
instructionVideoPlayer.pause();
}
private void restoreOverlayState()
{
prefs = getSharedPreferences(SAVE_PREFS, Context.MODE_PRIVATE);
if(prefs.getBoolean(IS_PAUSED, false))
{
pauseOverlay.setVisibility(View.VISIBLE);
pauseVideo();
}
else
{
pauseOverlay.setVisibility(View.GONE);
}
}
Edit: this only happens on the Nexus S (2.3.3) one of the phones I am testing on. The other Galaxy S(Froyo) does not have this error.
I figured out what I was doing Wrong. the OnCompletionListener was being called. The problem was I was running 2 media players and setting the same onCompletionlistener to them accidentally as I was calling initPlayer twice. Once in surfaceCreated and again at the end of onResume(). Either the Galaxy S is messed up or it has weird error checking becasue this problem didnt show up there.
I need help/pointer to doc/sample code on how to load multiple audio files from a specific folder on the SD card and have it play a random file back(i think i can figure out the last step if i could just figure out how to load multiple files). Here is my incredibly poorly written app so far, don't judge too harshly as I'm learning as I go.
public class zazenbox extends Activity implements OnClickListener{
File filecheck;
MediaPlayer player;
Button playerButton;
Integer var1;
String path1;
AlertDialog.Builder alertbox;
public void onClick(View v) {
if (v.getId() == R.id.play) {
playPause();
}
}
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
demoLoad();
playerButton = (Button) this.findViewById(R.id.play);
playerButton.setText(R.string.stop);
playerButton.setOnClickListener(this);
demoPlay();
}
#Override
public void onPause() {
super.onPause();
player.pause();
}
#Override
public void onStop() {
super.onStop();
player.stop();
}
private void demoLoad() {
dirfilecheck();
player = new MediaPlayer();
player.setLooping(true);
try {
player.setDataSource(path1);
player.prepare();
}
catch (IOException e) { e.printStackTrace(); }
catch (IllegalArgumentException e) { e.printStackTrace(); }
catch (IllegalStateException e) { e.printStackTrace(); }
}
private void dirfilecheck() {
filecheck = new File(Environment.getExternalStorageDirectory() + "/zazenbox");
if(filecheck.exists() && filecheck.isDirectory()) {
// load files.
var1 = 1;
path1 = filecheck + "/bm10" + var1 + ".wav";
} else {
// create folder, dl sample loop, and instruct user how to add music/loops.
filecheck.mkdirs();
alertbox = new AlertDialog.Builder(this);
alertbox.setMessage("Please put loopable media in zazenbox on your sdcard.");
alertbox.setNeutralButton("Ok, I will.", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface arg0, int arg1) {
Toast.makeText(getApplicationContext(), "Please plug in your device now", Toast.LENGTH_LONG).show();
}
});
alertbox.show();
}
}
private void demoPause() {
player.pause();
playerButton.setText(R.string.play);
}
private void demoStop() {
player.stop();
playerButton.setText(R.string.play);
}
private void demoPlay() {
player.start();
playerButton.setText(R.string.stop);
}
private void playPause() {
if(player.isPlaying()) {
demoStop();
//demoPause();
//player.release();
var1++;
path1 = filecheck + "/bm10" + var1 + ".wav";
/*try {
player.setDataSource(path1);
player.prepare();
}
catch (IOException e) { e.printStackTrace(); }
catch (IllegalArgumentException e) { e.printStackTrace(); }
catch (IllegalStateException e) { e.printStackTrace(); }*/
//player.start();
//demoPlay();
} else {
//do stuff
demoPlay();
}
}
}
Memory is extremely limited on mobile devices, so you wouldn't want to load songs you're not going to play. So what you should do is find all of the audio files in that folder, and then choose one and THEN load and play it.
You just need to stop the current player and create a new instance.
MediaPlayer player = MediaPlayer.create(this, Uri.parse("Path/To/Media"));
player.start();
// change track
player.stop();
player = MediaPlayer.create(this, Uri.parse("New/Path/To/Media"));
player.start();