Reputation: 1559
I need to play multiple (correct :2 ) mp3 files loaded from my assets when a button is clicked. If the button is again clicked 2 new songs should be played and the old ones should be stopped immidiatelly.The process is on going... At the moment I have achieved this by stupidly creating 2 mediaPlayer instances in 2 separate methods that basically have the same body . The caller is an onTouch method and ,within it, first I call method 1 ,then sleep for 2 secs ,then call method 2. I m sure there must be a way for this to be more elegant code? For example I have implemented some listeners that are just sitting there (Actually tried to make this work but totally screwed up with Illegal States all over the place ). Ideally I would like to use 1 MediaPlayer and one method for playing every sound in my app.
int carouzelIndex = 0
@Override
public boolean onTouch(MotionEvent e, int scaledX, int scaledY) {
...
if (e.getAction() == MotionEvent.ACTION_UP) {
carouzelIndex++;
Assets.playMusic1("music1.ogg",false);
Thread thread = new Thread(){
public void run(){
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
e.printStackTrace();
}
Assets.playMusic2("music2.ogg",false);
}
}
}
}
Now my player methods 1 and 2 (playMusic1() and playMusic2() )are the same. Both are instansiating different MediaPlayers and for the shake of simplicity I write just one copy in the post
Public class Assets
MediaPlayer mediaPlayer;
public static void playMusic(String filename, boolean looping) {
AssetFileDescriptor afd = null;
Log.d("Assets", "playing music");
if (mediaPlayer == null) {
mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.setLooping(looping);
}
try {
if (mediaPlayer != null) {
mediaPlayer.stop();
mediaPlayer.release();
mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.setLooping(looping);
}
afd = GameMainActivity.assets.openFd(filename);
mediaPlayer.setDataSource(afd.getFileDescriptor(),
afd.getStartOffset(), afd.getLength());
afd.close();
mediaPlayer.prepareAsync();
mediaPlayer.setOnPreparedListener(new OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
if (!mp.isPlaying())
mp.start();
}
});
mediaPlayer.setOnErrorListener(new OnErrorListener() {
@Override
public boolean onError(MediaPlayer mp, int what, int extra) {
return false;
}
});
mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
mediaPlayerIsFinished = true;
mp.reset();
}
});
mediaPlayer.setOnInfoListener(new OnInfoListener() {
@Override
public boolean onInfo(MediaPlayer mp, int what, int extra) {
// TODO Auto-generated method stub
return false;
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
Upvotes: 4
Views: 661
Reputation: 307
You can try something like this. Use a single mediaplayer in a single thread. It is an asynchronous operation so it will go on also if the thread is paused. I think it would work.
private Thread t = null;
private MediaPlayer mediaPlayer;
...
Button b=findViewById(R.id.yourButtonId);
b.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v){
//if button had previously clicked stop audio reproduction
if(mediaPlayer.isPlaying()) mediaPlayer.stop();
if(t.isAlive()) t.stop();
String[] files;
//Here you have to set your filenames in the array
...
...
//Now play that audio
playMusic(files, false);
}
});
...
protected static void playMusic(String[] files, boolean looping){
AssetFileDescriptor afd = null;
Log.e("Assets", "Playing music");
t=new Thread(){
@Override
public void run(){
//Initialize mediaPlayer
for(String filename:files){
mediaPlayer=new MediaPlayer();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.setLooping(looping);
afd = GameMainAcivity.assets.openFd(filename);
mediaPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(),afd.getLength());
afd.close();
mediaPlayer.prepareAsync();
mediaPlayer.setOnPreparedListener(new OnPreparedListener(){
@Override
public void onPrepared(MediaPlayer mp){
if(!mp.isPlaying()) mp.start();
}
});
//while audio is playing wait in this position
while(mediaPlayer.isPlaying()){
this.wait(100);
}
//now loop can restart with the other filename that has
//to be reproduced
}
}
};
t.start();
}
Upvotes: 1
Reputation: 6813
For immediate playback you need two MediaPlayer set up and chained together via OnCompletionListener
You can do it like this:
Note that I also deleted some unnecessary overrides, you might add them again if you need them.
Public class Assets{
MediaPlayer mediaPlayer;
MediaPlayer mediaPlayer2;
boolean mediaplayer2prepared = false;
boolean mediaplayer1finished = false;
public static void playMusic(String filename, boolean looping, String filename2, boolean looping2) {
AssetFileDescriptor afd = null;
Log.d("Assets", "playing music");
if (mediaPlayer == null) {
mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.setLooping(looping);
mediaplayer1finished = false;
}
if (mediaPlayer2 == null) {
mediaPlayer2 = new MediaPlayer();
mediaPlayer2.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer2.setLooping(looping);
mediaplayer2prepared = false;
}
try {
if (mediaPlayer != null) {
mediaPlayer.stop();
mediaPlayer.release();
mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.setLooping(looping);
mediaplayer1finished = false;
}
if (mediaPlayer2 != null) {
mediaPlayer2.stop();
mediaPlayer2.release();
mediaPlayer2 = new MediaPlayer();
mediaplayer2prepared = false;
mediaPlayer2.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer2.setLooping(looping);
}
afd = GameMainActivity.assets.openFd(filename);
mediaPlayer.setDataSource(afd.getFileDescriptor(),
afd.getStartOffset(), afd.getLength());
afd.close();
mediaPlayer.setOnPreparedListener(new OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
if (!mp.isPlaying())
mp.start();
}
});
mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
mediaPlayerIsFinished = true;
mp.reset();
if(mediaplayer2prepared)
mediaplayer2.start();
mediaplayer1finished = true;
}
});
mediaPlayer.prepareAsync();
afd2 = GameMainActivity.assets.openFd(filename2);
mediaPlayer2.setDataSource(afd2.getFileDescriptor(),
afd2.getStartOffset(), afd2.getLength());
afd2.close();
mediaPlayer2.setOnPreparedListener(new OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
mediaPlayerIsFinished = true;
mp.reset();
mediaplayer2prepared = true;
if(mediaplayer1finished && !mp.isPlaying()){
mp.start();
}
}
});
mediaPlayer2.setOnCompletionListener(new OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
mediaPlayerIsFinished = true;
mp.reset();
}
});
mediaPlayer2.prepareAsync();
} catch (Exception e) {
e.printStackTrace();
}
}
}
To start both mediaplayers in succession simply do Assets.playMusic("music1.ogg",false, "music2.ogg",false);
Upvotes: 1