7

I'm playing an audio clip using OpenSL ES. In my code I have

    audioManager.setMode(AudioManager.MODE_IN_CALL);
    audioManager.setSpeakerphoneOn(true);

to force audio through the speaker while the headset is plugged in. It works fine, but I can't control the volume. Pressing the volume buttons while the clip is playing makes the volume seekbar appear and move, but the volume doesn't change. Calling setVolumeControlStream(AudioManager.STREAM_VOICE_CALL) or setVolumeControlStream(AudioManager.STREAM_MUSIC) before playing doesn't seem to help. Changing any of the volumes outside of my app (e.g. in the Android settings) doesn't affect the playing volume. Volume control works well on both headset and speaker when no routing is applied.

I've also tried routing the audio to the speaker using this code I found in another answer

    Class audioSystemClass = Class.forName("android.media.AudioSystem");
    Method setForceUse = audioSystemClass.getMethod("setForceUse", int.class, int.class);
    // First 1 == FOR_MEDIA, second 1 == FORCE_SPEAKER. To go back to the default
    // behavior, use FORCE_NONE (0).
    setForceUse.invoke(null, 1, 1);

but it doesn't work on my Android 4.3 Nexus 4. I need the most compatible way to to that anyway.

Any ideas? Thanks.

Nitrooo
  • 73
  • 1
  • 4

1 Answers1

5

Here is a couple ideas:

  1. MODE_IN_CALL sets all sorts of priority/policy on STREAM_VOICE_CALL. During this time, other STREAM may loose volume control focus. See if your audio clip is played over STREAM_VOICE_CALL.

  2. MODE_IN_COMMUNICATION (for VoIP) may be a better fit for you. MODE_IN_CALL is for cellular call and can degrade your audio quality.

  3. You may want to try grab audio focus and see if that helps. http://developer.android.com/training/managing-audio/audio-focus.html

Kevin I. Wu
  • 226
  • 1
  • 4
  • Setting the stream type to `SL_ANDROID_STREAM_VOICE` in the OpenSL player did the trick, thanks. Now I can control the volume while the clip is playing (handset seekbar appears), but I'd like to be able to set the volume even when it's not playing. Calling `setVolumeControlStream(AudioManager.STREAM_VOICE_CALL)` in the Activity's `onResume()` method apparently makes you control the call volume (handset seekbar appears), but when you play the clip the volume is the last you set while playing. I also tried `setStreamVolume(AudioManager.STREAM_VOICE_CALL, vol, 0)` but it's just ignored. – Nitrooo Nov 03 '13 at 21:24
  • I've just found out that if I omit the `audioManager.setSpeakerphoneOn(true)` call, letting the audio play through the device's earpiece instead of the speaker, the volume level you can set when the clip is not playing matches the volume level you can see (and hear) while playing, which is the behavior I'd like to achieve with the speaker on. This means that calling `setVolumeControlStream(AudioManager.STREAM_VOICE_CALL)` makes the volume buttons control the earpiece volume. I want the volume buttons to control the speaker level instead. Is there any hack to do that? – Nitrooo Nov 04 '13 at 04:44
  • Glad that the first solution works for you. Now that your audio STREAM_VOICE_CALL matches the MODE_IN_CALL, volume control is a bit different system. Android have several different volume setting for voice_call, music, bluetooth, alarm, notification, etc. When audio output from internal, volume of STREAM_VOICE_CALL is used. Output from headset, volume STREAM_VOICE_CALL is used for MODE_IN_CALL/MODE_IN_COMMUNICATION. In your case of speaker, you need to control the volume of STREAM_MUSIC even though you are playing STREAM_VOICE_CALL. Hope this helps – Kevin I. Wu Nov 04 '13 at 16:14
  • Routing the audio in the `onResume()` method worked. Before I was calling `setMode(MODE_IN_COMMUNICATION); setSpeakerphoneOn(true);` just before playing the audio clip and setting it back to `MODE_NORMAL` after playing. Your comment helped me, thank you very much again. The only unwanted side effect now is that some sounds, like the tap clicks, are played through the speaker when my activity is showing. That's acceptable, but not ideal. I could probably keep the routing off and override the volume buttons turning the routing on and off, but it feels a bit hacky and I don't like it. – Nitrooo Nov 04 '13 at 23:48
  • Setting MODE_IN_COMMUNICATION was the solution for me - this made volume control work, where MODE_IN_CALL did not. Thanks! – chrisdowney Jan 17 '17 at 21:19