I'm working on a Service
that plays a song picked from an ArrayList
.
The problem comes when I use prepare()
and prepareAsync()
methods, so here's the code:
public class MusicService extends Service implements MediaPlayer.OnPreparedListener{
private final static int DEF_VALUE = -1;
private Context mContext;
private ArrayList<Song> mSongsList;
private MediaPlayer mPlayer;
private boolean isPlaying = false;
private int mPosition;
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate(){
super.onCreate();
mContext = getApplicationContext();
mSongsList = new ArrayList<Song>();
mPlayer = new MediaPlayer();
setMusicPlayer();
}
public void setMusicPlayer(){
//Setting player properties
mPlayer.setWakeMode(mContext, PowerManager.PARTIAL_WAKE_LOCK);
mPlayer.setAudioSessionId(AudioManager.STREAM_MUSIC);
mPlayer.setOnPreparedListener(this);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
int mCommand = intent.getIntExtra("CMD", DEF_VALUE);
int mTrackSelected = intent.getIntExtra("TRACK_CLICKED", DEF_VALUE);
/** SERVICE COMMANDS
* 0 = SERVICE PERMISSIONS
* 1 = PLAY_PAUSE
* 2 = NEXT TRACK
* 3 = PREV TRACK
* 4 = SONG IN LIST
*/
switch (mCommand){
case 0:
GetTracks mGetSongs = new GetTracks();
mSongsList = mGetSongs.listAllSongs(mContext);
Log.d("test size arrayList", ""+mSongsList.size());
break;
case 1:
setPlayPause();
break;
case 2:
skipNextTrack();
break;
case 3:
skipPrevTrack();
break;
case 4:
if(mTrackSelected != DEF_VALUE){
mPosition = mTrackSelected;
setSongToPlay(mPosition);
}
break;
default:
Log.d("error cmd", "You shouldn't be here!");
break;
}
return START_STICKY;
}
private void skipPrevTrack() {
Log.d("method called:", "skipPrevTrack()");
if(mPosition == 0){
setSongToPlay(mPosition = mSongsList.size()-1);
} else setSongToPlay(--mPosition);
Log.d("test mPosition service", ""+mPosition);
}
private void skipNextTrack() {
Log.d("method called:", "skipNextTrack()");
if(mPosition == mSongsList.size()-1){
setSongToPlay(mPosition = 0);
} else setSongToPlay(++mPosition);
Log.d("test mPosition service", ""+mPosition);
}
private void setSongToPlay(int pos) {
Log.d("method called:", "setSongToPlay("+pos+")");
startSong(mSongsList.get(pos).getSongUri());
}
private void startSong(Uri uri){
try{
mPlayer.reset();
mPlayer.setDataSource(mContext, uri);
mPlayer.prepareAsync();
/** +++WORKS FINE WITH THIS CODE+++
mPlayer = MediaPlayer.create(mContext, uri);
mPlayer.start();
*/
} catch (Exception e){
e.printStackTrace();
}
}
private void setPlayPause() {
Log.d("method called:", "setPlayPause()");
}
@Override
public void onPrepared(MediaPlayer mp) {
mp.start();
}
}
LOG:
12-19 16:12:18.325 4013-4013/sebbsoft.myApp D/method called:: setSongToPlay(3)
12-19 16:12:18.341 4013-4013/sebbsoft.myApp D/test song playing: Fiori del male ft. Sfera Ebbasta
12-19 16:12:18.363 4013-4013/sebbsoft.myApp D/MediaPlayer: setSubtitleAnchor in MediaPlayer
12-19 16:12:18.428 4013-4028/sebbsoft.myApp E/MediaPlayer: error (1, -19)
How can I solve it?
Finally solved it! After a lot of trial & error!! This is the line that causes it for me:
mMediaPlayer.setAudioSessionId(AudioManager.STREAM_MUSIC);
The API doc for setAudioSessionId doesn't indicate any alternative or any issue on still using it which made it hard to debug. But I saw setAudioStreamType just below it, which is deprecated and suggests setAudioAttributes instead, w/c is added in API 21.
So I changed the above code to this:
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
mMediaPlayer.setAudioAttributes(new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_MEDIA)
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
.build());
} else {
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
}
And now it works!
By the way, as you can see, I checked only against version N (API 24) and above instead of from LOLLIPOP even though setAudioAttributes
was added in API 21, because I only encounter this issue on Nougat devices, setAudioSessionId
works up to Marshmallow devices for me so... don't wanna break anything that's already working.
I do hope someone would stop by and explain why this happens and what the error really means.
Hope this saves anyone days of headache :)
EDIT:
For anyone Googling around, I also changed the original mMediaPlayer.setAudioSessionId
to mMediaPlayer.setAudioStreamType
, as pointed out by Eugen Pechanec. See his comment and answer for details.
You would also want to change from checking against Build.VERSION_CODES.N
to Build.VERSION_CODES.LOLLIPOP
with that.