Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

(Android MediaPlayer) How am I supposed to call setAudioStreamType() if MediaPlayer.create() implicitly calls prepare()?

I am writing an Android alarm application that uses a Service in order to play the alarm tone. Currently, I am able to get the audio to play, but it plays in a form that can be muted by turning down the device's volume. Thus, I am trying to add a call to setAudioStreamType(AudioManager.STREAM_ALARM); to prevent this.

I have the following for my onStartCommand() function for the service:

MediaPlayer mMP;    
@Override
    public int onStartCommand(Intent intent, int flags, int startId)
    {
        try
        {
            mMP = MediaPlayer.create(this, R.raw.alarm);
            mMP.setAudioStreamType(AudioManager.STREAM_ALARM);
            mMP.setLooping(true);
            //mMP.prepare(); commented out since prepare() is called in create
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        if (mMP != null) mMP.start();

        return START_STICKY;
    }

My problem is that with the call to setAudioStreamType(), the MediaPlayer never plays the audio. If I comment that line out, the audio plays.

With the line in, I get the following runtime error(s):

04-10 19:32:03.115: E/MediaPlayer(3411): setAudioStream called in state 8

04-10 19:32:03.115: E/MediaPlayer(3411): error (-38, 0)

04-10 19:32:03.115: E/MediaPlayer(3411): start called in state 0

04-10 19:32:03.115: E/MediaPlayer(3411): error (-38, 0)

04-10 19:32:03.115: E/MediaPlayer(3411): Error (-38,0)

04-10 19:32:03.115: E/MediaPlayer(3411): Error (-38,0)

Some research (I can't find the link now) told me that setAudioStreamType() can't be called after prepare() has been called, and that create() implicitly calls prepare().

In any regard, how am I supposed to setAudioStreamType() without such an error?

like image 224
finiteloop Avatar asked Apr 10 '12 23:04

finiteloop


2 Answers

You can either call mp.reset() and then set the stream type, data source, and then prepare. Alternately just use the default constructor and handle the initialization yourself.

EDIT:

Resources res = getResources();
AssetFileDescriptor afd = res.openRawResourceFd(R.raw.alarm);

mp.reset();
mp.setAudioStreamType(AudioManager.STREAM_ALARM);
mp.setLooping(true);
mp.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
mp.prepare();
mp.start();
like image 118
Kevin Coppock Avatar answered Nov 12 '22 03:11

Kevin Coppock


Accepted answer was throwing an IllegalStateException. This is working

MediaPlayer mediaPlayer = new MediaPlayer();

try {
  mediaPlayer.setDataSource(
          this,
          getCustomToneUri()
  );

  mediaPlayer.setAudioStreamType(AudioManager.STREAM_NOTIFICATION);

  mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
    @Override
    public void onPrepared(MediaPlayer mp) {
      mp.start();
    }
  });

  mediaPlayer.prepareAsync();
} catch (IOException e) {
  e.printStackTrace();
}
like image 3
Maragues Avatar answered Nov 12 '22 03:11

Maragues