Wednesday, July 22, 2015

Force media through speaker in Android activity


In one of my projects, one of the requirements was to force the audio through speaker when a temperature measuring device (Thermodo) was plugged into headset jack. This device fits in the 3.5mm jack and causes the audio to be routed to the headset instead of speaker.

After attempting a number of workarounds for more than a week, I was able to play the sound through speaker even if the headset or any 3.5mm device is plugged into the jack.

There are two methods of doing it as mentioned below.

1. Activity
2. Background Service

I will explain the first way of doing it in this blog when you wish to play audio in an Activity using its context. This can include playing short audios on click of a button, or a welcome audio when an activity is launched and so on. I would provide sample for playing audio only.

Set the audio Uri according to your audio file. You can also use system ringtones.
Uri uri = Uri.parse("android.resource://" + MainApplication.getContext().getPackageName() + "/" + resId




Create a MediaPlayer instance. You can do that locally if you wish to use this instance locally. In most of the cases, you might need to stop or pause media based on some events. It is preferable to create the instance as a global one and use it wherever needed.
MediaPlayer player = new MediaPlayer();


Reset the media player to clear all settings. The next step is the most important part as it allows you to set the audio stream type for your media player. You can set it to the following streams:
1. STREAM_ALARM //plays in both headset and speaker
2. STREAM_MUSIC // only plays in headset
3. STREAM_NOTIFICATION // plays in both headset and speaker
4. STREAM_RING // plays in both headset and speaker (I used this)
5. STREAM_SYSTEM
6. STREAM_VOICE_CALL
The code is as below:
player.reset();
player.setAudioStreamType(AudioManager.STREAM_RING);

After setting the stream, you need to set the data source of the audio and prepare the player.
try {
     player.setDataSource(context, uri);
     player.prepareAsync();
}
catch (IOException e) {
      e.printStackTrace();
}

That covers most of the work. When the audio devices are ready to play, you can call play on the Media Player instance and that will play the sound.
player.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
        if(! mp.isPlaying())
        mp.start();
       }
    });

You can release the player when the audio has played completely. You can also stop the audio anywhere during its play duration by calling stop() api of Media Player.
player.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
           mp.stop();
           mp.release();
        }
    });

That's pretty much all about playing audio through different audio devices in a proper way. I will discuss about achieving the same using a Service in the next post. Catch you soon.