5

My requirement is to switch audio between Bluetooth and phone speaker as per user selection. Below is the code snippet:

//AudioTrack for incoming audio to play as below:

    int mMaxJitter = AudioTrack.getMinBufferSize(8000,               AudioFormat.CHANNEL_OUT_MONO,AudioFormat.ENCODING_PCM_16BIT);                                  
    new AudioTrack(AudioManager.STREAM_VOICE_CALL,8000,
           AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT,
           mMaxJitter, AudioTrack.MODE_STREAM);


//To register broadcast receiver for bluetooth audio routing
    IntentFilter ifil = new IntentFilter();
    ifil.addAction(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED);
    this.registerReceiver(<receiver instance>,ifil);

//To get AudioManager service
    AudioManager mAudioManager = (AudioManager)getSystemService(Context.AUDIO_SERVICE);

//Whenever user select to route audio to Bluetooth
    mAudioManager.setMode(AudioManager.MODE_IN_CALL);//tried setting with other mode also viz. MODE_NORMAL, MODE_IN_COMMUNICATION but no luck
    mAudioManager.startBluetoothSco();//after this I get AudioManager.SCO_AUDIO_STATE_CONNECTED state in the receiver
    mAudioManager.setBluetoothScoOn(true);
    mAudioManager.setSpeakerphoneOn(false);

//Whenever user select to route audio to Phone Speaker
    mAudioManager.setMode(AudioManager.MODE_NORMAL);
    mAudioManager.stopBluetoothSco();//after this I get      AudioManager.SCO_AUDIO_STATE_DISCONNECTED state in the receiver
    mAudioManager.setBluetoothScoOn(false);
    mAudioManager.setSpeakerphoneOn(true);

Issues: 1. I'm able to route audio but Behavior is inconsistent, sometimes it routes to phone speaker even if user choose to route to bluetooth(bluetooth is connected) 2. If audio is routed to phone speaker, volume becomes low(please don't say check the phone volume) 3. Only a few times I could observe audio routing is proper as per choice, if I repeat it becomes weird as I mentioned above.

Android version: Jellybean 4.3

Has anyone faced something similar behavior ?

Thanks!

user3482378
  • 191
  • 1
  • 5

3 Answers3

14

I got the reason of inconsistent audio routing, it was because I was setting phone speaker false, also I was using inappropriate mode... below combination worked for me:

//For BT
mAudioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
mAudioManager.startBluetoothSco();
mAudioManager.setBluetoothScoOn(true);

//For phone ear piece
mAudioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
mAudioManager.stopBluetoothSco();
mAudioManager.setBluetoothScoOn(false);
mAudioManager.setSpeakerphoneOn(false);

//For phone speaker(loadspeaker)
mAudioManager.setMode(AudioManager.MODE_NORMAL);
mAudioManager.stopBluetoothSco();
mAudioManager.setBluetoothScoOn(false);
mAudioManager.setSpeakerphoneOn(true);

Android version: 4.3

Thanks!

user3482378
  • 191
  • 1
  • 5
  • 1
    I found that for loudspeaker, I had to change to `MODE_NORMAL` if it came from BT, otherwise `MODE_IN_COMMUNICATION` – behelit Sep 19 '16 at 06:41
2

if it still relevant to someone, this is my solution:

(tested on samsung s7 sm-g9307 with android version 6.0.1)

public class AudioSourceUtil {

private static void reset(AudioManager audioManager) {
    if (audioManager != null) {
        audioManager.setMode(AudioManager.MODE_NORMAL);
        audioManager.stopBluetoothSco();
        audioManager.setBluetoothScoOn(false);
        audioManager.setSpeakerphoneOn(false);
        audioManager.setWiredHeadsetOn(false);
    }
}

public static void connectEarpiece(AudioManager audioManager) {
    reset(audioManager);
    audioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
}

public static void connectSpeaker(AudioManager audioManager) {
    reset(audioManager);
    audioManager.setSpeakerphoneOn(true);
}

public static void connectHeadphones(AudioManager audioManager) {
    reset(audioManager);
    audioManager.setWiredHeadsetOn(true);
}

public static void connectBluetooth(AudioManager audioManager) {
    reset(audioManager);
}

}

And for the usage by clicking a button (tab in tab layout):

/**
 * There are 3 scenarios for the audio source:
 * 1. No headphones and no bluetooth device: toggle phone/ speaker
 * 2. Headphones connected: toggle headphones/ speaker
 * 3. Bluetooth connected: toggle  phone/ speaker/ bluetooth
 *
 * @param tab
 */
private void handleTabAudioSourceClick(TabLayout.Tab tab) {
    View view = tab.getCustomView();
    ImageView icon = (ImageView) view.findViewById(R.id.imageViewIcon);
    int currentAudioSourceIdentifier = (Integer) view.getTag();

    if (audioManager.isWiredHeadsetOn() == false && BluetoothManager.isBluetoothHeadsetConnected() == false) {
        // No headphones and no bluetooth device: toggle phone/ speaker.
        if (currentAudioSourceIdentifier == R.drawable.tab_speaker) {
            // Current audio source is earpiece, moving to speaker.
            view.setTag(android.R.drawable.stat_sys_speakerphone);
            icon.setImageResource(android.R.drawable.stat_sys_speakerphone);
            AudioSourceUtil.connectSpeaker(audioManager);
        } else {
            // Current audio source is speaker, moving to earpiece.
            view.setTag(R.drawable.tab_speaker);
            icon.setImageResource(R.drawable.tab_speaker);
            AudioSourceUtil.connectEarpiece(audioManager);
        }
    } else if (audioManager.isWiredHeadsetOn()) {
        // Headphones connected: toggle headphones/ speaker.
        if (currentAudioSourceIdentifier == android.R.drawable.stat_sys_speakerphone) {
            // Current audio source is speaker, moving to headphones.
            view.setTag(android.R.drawable.stat_sys_headset);
            icon.setImageResource(android.R.drawable.stat_sys_headset);
            AudioSourceUtil.connectHeadphones(audioManager);
        } else {
            // Current audio source is headphones, moving to speaker.
            view.setTag(android.R.drawable.stat_sys_speakerphone);
            icon.setImageResource(android.R.drawable.stat_sys_speakerphone);
            AudioSourceUtil.connectSpeaker(audioManager);
        }
    } else if (BluetoothManager.isBluetoothHeadsetConnected()) {
        // Bluetooth connected: toggle  phone/ speaker/ bluetooth.
        if (currentAudioSourceIdentifier == R.drawable.tab_speaker) {
            // Current audio source is earpiece, moving to speaker.
            view.setTag(android.R.drawable.stat_sys_speakerphone);
            icon.setImageResource(android.R.drawable.stat_sys_speakerphone);
            AudioSourceUtil.connectSpeaker(audioManager);
        } else if (currentAudioSourceIdentifier == android.R.drawable.stat_sys_speakerphone) {
            // Current audio source is speaker, moving to bluetooth.
            view.setTag(android.R.drawable.stat_sys_data_bluetooth);
            icon.setImageResource(android.R.drawable.stat_sys_data_bluetooth);
            AudioSourceUtil.connectBluetooth(audioManager);
        } else {
            // Current audio source is bluetooth, moving to earpiece.
            view.setTag(R.drawable.tab_speaker);
            icon.setImageResource(R.drawable.tab_speaker);
            AudioSourceUtil.connectEarpiece(audioManager);
        }
    }
}
user3193413
  • 575
  • 7
  • 10
0

Use MediaRouter api's for this: https://developer.android.com/guide/topics/media/mediarouter

It is designed specially for this. Something like this:

mediaRouter = MediaRouter.getInstance(VideoCallingApp.getContext());
mediaRouteSelector = new MediaRouteSelector.Builder()
            .addControlCategory(MediaControlIntent.CATEGORY_LIVE_AUDIO)
            .build();
....

public void onStart() {
    mediaRouter.addCallback(mediaRouteSelector, mMediaRouterCallback,
            MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY);
    super.onStart();
}

@Override
public void onStop() {
    mediaRouter.removeCallback(mMediaRouterCallback);
    super.onStop();
}

...and when you want to switch audio device then use mediaRouter.getRoutes() and mediaRouter.selectRoute(route) API's.

Fedir Tsapana
  • 1,283
  • 16
  • 19