来电后蓝牙 SCO 失败

Posted

技术标签:

【中文标题】来电后蓝牙 SCO 失败【英文标题】:Bluetooth SCO fails after incoming call 【发布时间】:2014-06-08 08:17:13 【问题描述】:

我正在尝试通过 SCO 发送应用程序的所有音频。

我能够成功发送音频,

但是当有来电时,我需要断开与 SCO 的连接,以便应用程序音频不会干扰通话,

问题是,当我尝试在通话后将音频重新路由到 SCO 时,它不起作用。

这是我用来将音频发送到 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);




当我正确调用stopBluetooth() 时,应用程序的音频不再发送到耳机,

但是当我打电话给restartBluetooth() 时,音频不是按预期从耳机播放,而是从手机扬声器播放。

【问题讨论】:

我也在尝试通过蓝牙将音频发送到特定的应用程序但无法到达这里是我的查询***.com/questions/24134223/… 【参考方案1】:

通话结束后SCO链接是否可能被关闭?如果是这种情况,则还必须启动 SCO 链接以及路由音频。

您是否尝试过在 restartBluetooth() 中调用 enableBluetoothSCO()

【讨论】:

【参考方案2】:

您可能需要致电:

aM.startBluetoothSco(); aM.setBluetoothScoOn(true);

设置模式后。

【讨论】:

【参考方案3】:

在你的重启函数中再次初始化一切,看看它是否有效。像这样:

public static void restartBluetooth()
    enableBluetooth(getApplicationContext());

如果这有效,则意味着当调用结束时,最后一次初始化由于某种原因丢失。

【讨论】:

【参考方案4】:

对于任何对此仍有疑问的人,有一些事情需要做。您需要做的第一件事是跟踪手机状态。你可以在这里看到如何做到这一点: How to know Phone call has ended?

当状态为空闲时,表示来电已结束。现在,如果您此时尝试重新连接蓝牙,您会发现它仍然无法正常工作,因为调用“释放”蓝牙设备需要一段时间(大约 2 秒)。 因此,您有两个选择,稍等片刻然后尝试重新连接,或者您可以将另一个侦听器添加到 BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED。

然后您可以添加一个全局布尔值 isIdle,当 TelephonyManager.CALL_STATE_IDLE 时为真,当 TelephonyManager.CALL_STATE_OFFHOOK 时为假(否则您将在来电期间重新连接到蓝牙)。此时当BluetoothHeadset.STATE_DISCONNECTED和isIdle为真时,再重新连接蓝牙。

@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;
    

【讨论】:

【参考方案5】:

Google Doc say's that

“电话应用程序始终优先使用 SCO 连接进行电话。如果在电话通话时调用此方法,它将被忽略。同样,如果在应用程序使用时接收或发送呼叫SCO 连接,应用程序的连接将丢失,并且不会在呼叫结束时自动返回。"

因此,当通话断开时,您必须通过调用 startBluetoothSco()

重新建立连接

【讨论】:

以上是关于来电后蓝牙 SCO 失败的主要内容,如果未能解决你的问题,请参考以下文章

489次成功连接后android蓝牙连接失败

连接蓝牙设备失败

蓝牙连接手表后微信语音来电不响铃

转蓝牙物理链路类型:SCO和ACL链路

带有日产汽车收音机的安卓蓝牙 SCO

蓝牙 SCO 到单个 android 应用程序,而不是整个 android 系统