MediaPlayer skips files if previous music file is short in length - android

I have a music service class in which I have a method called playNext().
public void playNext() {
setSong(songPosn + 1);
playSong();
}
and the playSong() method is,
public void playSong() {
if(player != null){
if(player.isPlaying()){
player.stop();
}
}
//play a song
isPaused = false;
isComplete = false;
isPrepared = false;
player = new MediaPlayer();
player.setAudioStreamType(AudioManager.STREAM_MUSIC);
player.setOnPreparedListener(this);
player.setOnCompletionListener(this);
//get song
Song playSong = songs.get(songPosn);
//get id
long currSong = playSong.getID();
//set uri
Uri trackUri = ContentUris.withAppendedId(
android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
currSong);
try {
player.setDataSource(getApplicationContext(), trackUri);
} catch (Exception e) {
Log.e("MUSIC SERVICE", "Error setting data source", e);
}
try {
player.prepare();
} catch (IOException e) {
e.printStackTrace();
}
}
The problem is when a song is played which has a very short length, player skips more than 1 song in the songs list. Even though, only 1 is incremented in the playNext() method.
Note: It doesn't happen every time. But most of the time. I cannot figure out the problem. And that short music file is a Facebook pop up sound which is less than 0 second in duration.

Related

Mediaplayer is playing random songs

Im using the following code to play music.
if (mMediaPlayer.isPlaying()) {
mMediaPlayer.reset();
mMediaPlayer = new MediaPlayer();
try {
mMediaPlayer.setDataSource(MainActivity.localTrackList.get(MainActivity.currentOffset).getPath());
} catch (IOException e) {
e.printStackTrace();
}
mMediaPlayer.prepareAsync();
} else {
mMediaPlayer = new MediaPlayer();
try {
mMediaPlayer.setDataSource(MainActivity.localTrackList.get(MainActivity.currentOffset).getPath());
} catch (IOException e) {
e.printStackTrace();
}
mMediaPlayer.prepareAsync();
}
Explanation:
when the user clicks a song for the first time, else loop will be
executed.
If the user clicks a song when the mediaplayer is playing a song already, if loop will
be executed
In my if loop, Im resetting the mediaplayer before setting the data source so it calls the onCompletion listener.
Follwing is my onCompletionListener.
mMediaPlayer.setOnCompletionListener(mp -> {
MainActivity.nextTrackController.performClick();
});
Following is my nextTrackController onClickListener.
MainActivity.nextTrackController.setOnClickListener(v -> {
try {
if (MainActivity.currentOffset < (MainActivity.localTrackList.size() - 1)) {
if (mMediaPlayer.isPlaying()) {
mMediaPlayer.stop();
mMediaPlayer.reset();
} else {
mMediaPlayer.reset();
}
MainActivity.currentOffset = MainActivity.currentOffset + 1;
mMediaPlayer.setDataSource(MainActivity.localTrackList.get(MainActivity.currentOffset).getPath());
mMediaPlayer.prepareAsync();
} else {
if (mMediaPlayer.isPlaying()) {
mMediaPlayer.stop();
mMediaPlayer.reset();
}
MainActivity.currentOffset = 0;
mMediaPlayer.setDataSource(MainActivity.localTrackList.get(MainActivity.currentOffset).getPath());
mMediaPlayer.prepareAsync();
}
} catch (Exception ex) {
}
});
the problem is that,
If the media player is playing and if the user is clicking a song, it is not playing the specific song that had been clicked but it plays some random song.
If the song finished playing, it plays a random song instead of the next song. How can i be able to sort this out?

Prevent mediaplayer from calling onCompletionListener

I'm using the following code to play music when an user selects a song from the listview.
if (mMediaPlayer.isPlaying()) {
mMediaPlayer.reset();
try {
mMediaPlayer.setDataSource(MainActivity.localTrackList.get(MainActivity.currentOffset).getPath());
} catch (IOException e) {
e.printStackTrace();
}
mMediaPlayer.prepareAsync();
} else {
mMediaPlayer = new MediaPlayer();
try {
mMediaPlayer.setDataSource(MainActivity.localTrackList.get(MainActivity.currentOffset).getPath());
} catch (IOException e) {
e.printStackTrace();
}
mMediaPlayer.prepareAsync();
}
mMediaPlayer.reset(); is calling the onCompletionListener. In my oncompletionListener, I'm playing the next song and hence instead of playing the selected song, it plays the next song in the listview. Is there by any ways I can prevent calling onCompletionListener and play only the song that's selected from listview?
You could do something like this.
boolean isMediaPlayerReset = false;
MediaPlayer mMediaPlayer = null;
//on list item click
if(mMediaPlayer.isPlaying()){
isMediaPlayerReset = true;
mMediaPlayer.reset();
try {
mMediaPlayer.setDataSource("/path");
} catch (IOException e) {
e.printStackTrace();
}
mMediaPlayer.prepareAsync();
}
mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mp) {
if(isMediaPlayerReset){
isMediaPlayerReset = false;
return;
}
//play next song
}
});

Shuffle songs in music player

I’m just starting Android development and Java, and this is my first app to get acquainted with Android development. I’m almost done with the app, the only thing left is shuffling songs. I tried many steps to get it right, and I’ve scoured the web and SO for related question, yet I still can’t get it right.
This snippet of code is in my Service class, Playlist is passed from Main Activity:
public void setPlayList(ArrayList<SongModel> playlist) {
playList = playlist;
//Arraylist of integer to hold the number of indices
list = new ArrayList<Integer>();
for(int i =0; i <= playList.size();i++){
list.add(i);
}
Collections.shuffle(list, new Random(System.nanoTime()));
}
The code below is how songs are played, this snippet is in configPlayBack() method that plays the song from the song id:
long item = 0;
item = playList.get(MusicPref.isShuffle(this)? list.get(position): position).getSongId();
the snippet for playing next song is:
public void playNext() {
position++;
if (position >= playList.size()) {
position = 0;
}
configPlayBack();
}
But the songs are still playing serially.
EDIT:
public void configPlayBack(){
prepared = true;
player.reset();
if ( playList.size()>0){
long item = 0;
item = playList.get(MusicPref.isShuffle(this)? list.get(position):position).getSongId();
playItem(item);
}
}
public void playItem(long item){
Uri base = android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
Uri trackUri = ContentUris.withAppendedId(base, item);
try{
player.setDataSource(getApplicationContext(), trackUri);
}
catch(Exception e){
Log.e(TAG, "Errror setting data source", e);
}
try{
player.prepare();
}
catch(Exception ee)
{
ee.printStackTrace();
Log.e(TAG, "Error setting data source", ee);
Toast.makeText(getApplicationContext(), "Song corrupt or not supported", Toast.LENGTH_SHORT).show();
ee.printStackTrace();
isReady = false;
}
player.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
isReady = true;
setPlayState();
getAudioFocus();
mp.start();
updateNotificationPlayer();
updatePlayback();
updateSeek();
player.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mp) {
isReady = false;
mp.reset();
playNext();
}
});
}
});
}
Okay you are shuffling your newly created list with
Collections.shuffle(list, new Random(System.nanoTime()));
but you are still using the old playlist
item = playList.get(MusicPref.isShuffle(this)? list.get(position): position).getSongId();
And I am not sure why you are using that line at all. Change it simply to
item = list.get(position).getSongId();

Multiple instance of media player issue in android

I am working with MediaPlayer in Android. I have all the list of songs name and URLs of songs from server. when I click on any item a song from server is played in MediaPlayer. Here is my code for playing song on click of "Listview" item.
txtEndTimingForMediaPlayer.setText("");
txtStarTimingForMediaPlayer.setText("");
seekBarPlayer.setProgress(0);
// this code is for stop current playing song and release media player
if(mediaPlayer!=null && mediaPlayer.isPlaying()){
mediaPlayer.stop();
mediaPlayer.reset();
mediaPlayer.release();
mediaPlayer=null;
}
// start new song for play
mediaPlayer=new MediaPlayer();
Uri myUri1 = Uri.parse(url);
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
try {
mediaPlayer.reset();
mediaPlayer.setDataSource(getActivity(), myUri1);
mediaPlayer.prepareAsync();
mediaPlayer.setOnPreparedListener(new OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer player) {
playPause=true;
player.start();
mediaFileLengthInMilliseconds = player.getDuration();
}
});
mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mp) {
playPause=false;
btnPlayPause.setBackgroundResource(R.drawable.icon_play);
}
});
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
Now issue with this code is when I click continuously on song, then same song plays multiple time. how to avoid this multiple instance issue.
I think if(mediaPlayer!=null && mediaPlayer.isPlaying()) is not true when you click too fast to play same song and then mediaPlayer=new MediaPlayer(); is creating new instance and play song, which will result in hearing same song multiple times. debug and check if code enter that if (condition)

Android: Stop sound files playing at once

In the application I am currently writing, a user is able to select an entry from the database and play the contents of that entry: an entry is made up of a number of sound files (without a limit). In my application, I return the URI locations of the sound files of an entry (which have been stored in my database) in a List. The code is as follows:
public void audioPlayer() {
// set up MediaPlayer
MediaPlayer mp = new MediaPlayer();
DatabaseHandler db = new DatabaseHandler(this);
Entry retrieveEntry = new Entry();
retrieveEntry = db.getEntry();
List<String> path = retrieveEntry.getAudioUri();
path.size();
System.out.println("PATH SIZE: " +path.size());
System.out.println("FILEZ: " + path);
Iterator<String> i = path.iterator();
String myAudio;
int count = 0;
while (i.hasNext()) {
System.out.println(count);
myAudio = i.next();
System.out.println("MY AUDIO: " + myAudio);
MediaPlayer player = MediaPlayer.create(this, Uri.parse(myAudio));
player.start();
player.stop();
player = MediaPlayer.create(this, Uri.parse(myAudio));
player.start();
count++;
}
}
My users require that there be user input for playing a file - is there a way to play the first file, then wait for the user to press the button, then play the second file, then wait for the user to press the button, etc.? At the moment, when the play button is pressed, all of the sound files that have been returned get played at the same time, rather than one after the other.
Thanks in advance for any help provided!
You can use this class to play a playlist. This will start one audio, when that audio finishes, it will start playing next audio till the end of the list. If you want to play the playlist in looping i.e start first audio after reaching end, then pass isLooping=true in startPlayingPlaylist(list,looping)
AudioPlayer player = new AudioPlayer();
player.startPlayingPlaylist(list, false);
Class
public class AudioPlayer{
MediaPlayer player = null;
ArrayList<String> playlist = null;
int position = 0;
public AudioPlayer() {
super();
// TODO Auto-generated constructor stub
}
public void startPlayingPlaylist(ArrayList<String> list, boolean looping){
playlist = list;
if(player!=null){
player.release();
}
if(playlist!=null && playlist.size()>0){
player = MediaPlayer.create(LMApplicaton.getInstance(),Uri.parse(playlist.get(position)));
player.setWakeMode(LMApplicaton.getInstance(), PowerManager.PARTIAL_WAKE_LOCK);
player.setLooping(looping);
player.start();
// Set onCompletion listener
player.setOnCompletionListener(new OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mp) {
position = position+1;
if(position<playlist.size()){
try {
player.reset();
player.setDataSource(playlist.get(position));
player.prepareAsync();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
} else if(player.isLooping()==true){
position = position%playlist.size();
try {
player.reset();
player.setDataSource(playlist.get(position));
player.prepareAsync();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
else if(player.isLooping()==false){
player.release();
player = null;
}
}
});
player.setOnPreparedListener(new OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
player.start();
}
});
}
}
public void pause(){
if(player!=null && player.isPlaying()){
player.pause();
}
}
public void play(){
if(player!=null && player.isPlaying()==false){
player.start();
}
}
public boolean isPlaying(){
return player.isPlaying();
}
public void release(){
if(player!=null){
player.release();
}
}
}
Edit:
The class below receives a list of audios, then plays first Audio. It plays next audio when user calls startNextAudio() You can use any one of these according to your requirements
public class AudioPlayer{
MediaPlayer player = null;
ArrayList playlist = null;
int position = 0;
public AudioPlayer() {
super();
// TODO Auto-generated constructor stub
}
public void startPlayingPlaylist(ArrayList<String> list){
playlist = list;
if(player!=null){
player.release();
}
if(playlist!=null && playlist.size()>0){
player = MediaPlayer.create(LMApplicaton.getInstance(),Uri.parse(playlist.get(position)));
player.setWakeMode(LMApplicaton.getInstance(), PowerManager.PARTIAL_WAKE_LOCK);
player.start();
// Set onCompletion listener
player.setOnPreparedListener(new OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
player.start();
}
});
}
}
public void startNextAudio(){
position = position+1;
if(position<playlist.size()){
try {
player.reset();
player.setDataSource(playlist.get(position));
player.prepareAsync();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
} else if(player.isLooping()==true){
position = position%playlist.size();
try {
player.reset();
player.setDataSource(playlist.get(position));
player.prepareAsync();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}else{
Log.i("AudioPlayer","Playlist reached at the end");
}
}
public void pause(){
if(player!=null && player.isPlaying()){
player.pause();
}
}
public void play(){
if(player!=null && player.isPlaying()==false){
player.start();
}
}
public boolean isPlaying(){
return player.isPlaying();
}
public void release(){
if(player!=null){
player.release();
}
}
}
One approach would be to implement the MediaPlayer.OnCompletionListener interface. This gives you the MediaPlayer.onCompletion() callback method which you could use like so:
#Override
public void onCompletion(MediaPlayer mp) {
if (i.hasNext) {
// ...hand mp the next file
// ...show the user the 'play next' button
}
}
Note you also will need to call the MediaPlayer.setOnCompletionListener() method in your setup.

Categories

Resources