Reputation: 4595
I am trying to send all the audio of an application via SCO.
I am able to successfully send the audio,
But when an incoming call comes I need to disconnect form SCO so that the application audio will not interfere with the call,
The problem is that, when I try to reroute the audio to SCO after the call, it does not work.
Here is the code I use to send the audio to SCO:
public class BluetoothManager {
// For Bluetooth connectvity
private static String TAG = "BluetoothManager";
private static BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
private static AudioManager aM;
/**
* Set the audio manager of the device.
* @param c: The context this method is called from
*/
public static void setAudioManager(Context c) {
aM = (android.media.AudioManager)c.getSystemService(Context.AUDIO_SERVICE);
}
/**
* Check if a Bluetooth headset is connected. If so, route audio to Bluetooth SCO.
*/
private static void initializeAudioMode(Context context) {
BluetoothProfile.ServiceListener mProfileListener = new BluetoothProfile.ServiceListener() {
public void onServiceConnected(int profile, BluetoothProfile proxy) {
if (profile == BluetoothProfile.HEADSET) {
BluetoothHeadset bh = (BluetoothHeadset) proxy;
List<BluetoothDevice> devices = bh.getConnectedDevices();
if (devices.size() > 0) {
enableBluetoothSCO();
}
}
mBluetoothAdapter.closeProfileProxy(profile, proxy);
}
public void onServiceDisconnected(int profile) {}
};
mBluetoothAdapter.getProfileProxy(context, mProfileListener, BluetoothProfile.HEADSET);
}
/**
* Bluetooth Connectvity
* The following methods are associated with enabling/disabling Bluetooth.
* In the future we may want to disable other sources of audio.
*/
private static void enableBluetoothSCO() {
aM.setMode(AudioManager.MODE_IN_CALL);
aM.startBluetoothSco();
aM.setBluetoothScoOn(true);
}
/** Right now, this simply enables Bluetooth */
@SuppressLint("NewApi")
public static boolean enableBluetooth(Context c) {
// If there is an adapter, enable it if not already enabled
if (mBluetoothAdapter != null) {
if (!mBluetoothAdapter.isEnabled()) {
mBluetoothAdapter.enable();
}
setAudioManager(c);
initializeAudioMode(c);
Log.e(TAG, "SCO: " + aM.isBluetoothScoOn());
Log.e(TAG, "A2DP: " + aM.isSpeakerphoneOn());
return true;
} else {
Log.v(TAG, "There is no bluetooth adapter");
return false;
}
}
/** Right now, this simply disables Bluetooth */
public static void disableBluetooth() {
// If there is an adapter, disabled it if not already disabled
if (mBluetoothAdapter != null) {
if (mBluetoothAdapter.isEnabled()) {
mBluetoothAdapter.disable();
}
} else {
Log.v(TAG, "There is no bluetooth adapter");
}
}
public static void restartBluetooth(){
aM.setMode(AudioManager.MODE_IN_CALL);
}
public static void stopBluetooth(){
aM.setMode(AudioManager.MODE_NORMAL);
}
}
When I call stopBluetooth()
correctly the audio of the application is not sent to the headset anymore,
But when I call restartBluetooth()
the audio plays NOT form the headset as intended, but from the phone speakers.
Upvotes: 6
Views: 2840
Reputation: 8364
Phone application always has the priority on the usage of the SCO connection for telephony. If this method is called while the phone is in call it will be ignored. Similarly, if a call is received or sent while an application is using the SCO connection, the connection will be lost for the application and NOT returned automatically when the call ends.
So when call is disconnected you must have to re-establish the connection by calling startBluetoothSco()
Upvotes: 2
Reputation: 11
For anyone that is still having issues with this, there are a few things that need to be done. The first thing you need to do is to keep track of the phone state. You can see how to do that here: How to know Phone call has ended?
When the state is idle that means the incoming call has ended. Now if you try to reconnect the bluetooth at this point you'll find it still does not work since it takes a while (roughly 2 seconds) for the call to "release" the bluetooth device. So you have two option, wait a bit then try to reconnect, or you can add another listener to BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED.
You can then add a global boolean value isIdle that is true when TelephonyManager.CALL_STATE_IDLE or false when TelephonyManager.CALL_STATE_OFFHOOK (Otherwise you'll reconnect to BlueTooth during the incoming call). At this point when BluetoothHeadset.STATE_DISCONNECTED and isIdle is true, then reconnect to Bluetooth.
@Override public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals((BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED))){
int state = intent.getIntExtra(BluetoothHeadset.EXTRA_STATE, BluetoothHeadset.STATE_AUDIO_DISCONNECTED);
switch(state) {
case BluetoothHeadset.STATE_AUDIO_DISCONNECTED:
if (isIdle){
//reconnect bluetooth
}
break;
}
}
if(("OFFHOOK").equals(intent.getStringExtra(TelephonyManager.EXTRA_STATE))) {
isIdle = false;
// turn bluetooth off
}
if(("IDLE").equals(intent.getStringExtra(TelephonyManager.EXTRA_STATE))) {
isIdle = true;
}
}
Upvotes: 1
Reputation: 4620
inside your restart function initialize everything again, and see if it works. like so:
public static void restartBluetooth(){
enableBluetooth(getApplicationContext());
}
if this works then it means that when the call is ended the last initialization is lost for some reason.
Upvotes: 1
Reputation: 738
You probably need to call:
aM.startBluetoothSco();
aM.setBluetoothScoOn(true);
after you set the mode.
Upvotes: 2
Reputation: 336
Is it possible that the SCO link was brought down after the call ended? If this is the case then the SCO link would also have to be brought up along with routing the audio.
Have you tried calling enableBluetoothSCO() within restartBluetooth()
Upvotes: 1