zoukankan      html  css  js  c++  java
  • android -- 蓝牙 bluetooth (五)接电话与听音乐

      1.蓝牙耳机接听电话

            这个就对应HFP(Hands-freeProfile),Free your Hand,蓝牙的初衷之一。先来看这个功能的场景,手机来电,手机与蓝牙耳机已连接,这时会优先触发蓝牙接听电话的代码流程,起步代码在phonesrccomandroidphone CallScreen.java的connectBluetoothAudio() /disconnectBluetoothAudio(),只看连接部分好了,注意下面代码里的注释,
    1. /* package */ void connectBluetoothAudio() {  
    2.   if (VDBG) log("connectBluetoothAudio()...");  
    3.   if (mBluetoothHeadset != null) {  
    4.       // TODO(BT) check return  
    5.       mBluetoothHeadset.connectAudio();  
    6.   }  
    7.   // Watch out: The bluetooth connection doesn't happen instantly;  
    8.   // the connectAudio() call returns instantly but does its real  
    9.   // work in another thread.  The mBluetoothConnectionPending flag  
    10.   // is just a little trickery to ensure that the onscreen UI updates  
    11.   // instantly. (See isBluetoothAudioConnectedOrPending() above.)  
    12.   mBluetoothConnectionPending = true;  
    13.   mBluetoothConnectionRequestTime = SystemClock.elapsedRealtime();  
             接下来就跳到蓝牙应用的管辖范围,代码在packages/apps/Bluetooth/src/com/android/bluetooth/hfp/HeadsetService.java,
    1. public boolean connectAudio() {  
    2.     HeadsetService service = getService();  
    3.     if (service == null) return false;  
    4.     return service.connectAudio();  
    5. }  
            很明显下一个目标是HeadsetService,直接看具体实现,这部分代码跳转都比较清晰,下面代码会先判断当前状态是否正确,关于HeadsetStateMachine几个状态可以参持这个/packages/apps/Bluetooth/src/com/android/bluetooth/hfp/HeadsetStateMachine.java的最前的代码注释。
    1. boolean connectAudio() {  
    2.      // TODO(BT) BLUETOOTH or BLUETOOTH_ADMIN permission  
    3.      enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");  
    4.      if (!mStateMachine.isConnected()) {  
    5.          return false;  
    6.      }  
    7.      if (mStateMachine.isAudioOn()) {  
    8.          return false;  
    9.      }  
    10.      mStateMachine.sendMessage(HeadsetStateMachine.CONNECT_AUDIO);  
    11.      return true;  
    12.  }  
           走进HeadsetStateMachine状态机,找到CONNECT_AUDIO分支,就看带Native的方法connectAudioNative(getByteAddress(mCurrentDevice));
    1. static jboolean connectAudioNative(JNIEnv *env, jobject object, jbyteArray address) {  
    2.     jbyte *addr;  
    3.     bt_status_t status;  
    4.   
    5.     if (!sBluetoothHfpInterface) return JNI_FALSE;  
    6.   
    7.     addr = env->GetByteArrayElements(address, NULL);  
    8.     if (!addr) {  
    9.         jniThrowIOException(env, EINVAL);  
    10.         return JNI_FALSE;  
    11.     }  
    12. //连接在这里  
    13.     if ( (status = sBluetoothHfpInterface->connect_audio((bt_bdaddr_t *)addr)) !=    
    14.          BT_STATUS_SUCCESS) {  
    15.         ALOGE("Failed HF audio connection, status: %d", status);  
    16.     }  
    17.     env->ReleaseByteArrayElements(address, addr, 0);  
    18.     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;  
    19. }  
           上面代码还可以进一步跟到下面/external/bluetooth/bluedroid/btif/src/btif_hf.c,到了这里其实流程已经结束了,对于这里消息流转估计要放到以后再写了
    1. static bt_status_t connect_audio( bt_bdaddr_t *bd_addr )  
    2. {  
    3.     CHECK_BTHF_INIT();  
    4.     if (is_connected(bd_addr))  
    5.     {  
    6.         BTA_AgAudioOpen(btif_hf_cb.handle);  
    7.         /* Inform the application that the audio connection has been initiated successfully */  
    8.         btif_transfer_context(btif_in_hf_generic_evt, BTIF_HFP_CB_AUDIO_CONNECTING,  
    9.                               (char *)bd_addr, sizeof(bt_bdaddr_t), NULL);  
    10.         return BT_STATUS_SUCCESS;  
    11.     }  
    12.     return BT_STATUS_FAIL;  
    13. }  
     

     2.在蓝牙列表中连接蓝牙耳机

         A2dp的连接过程,在蓝牙搜索结果列表连接一个蓝牙耳机,既然是从设备列表开始,所以起步代码自然是这个了
    1. DevicePickerFragment.java (settingssrccomandroidsettingsluetooth)     3884     2013-6-26  
    2.     void onClicked() {  
    3.       int bondState = mCachedDevice.getBondState();  
    4.       if (mCachedDevice.isConnected()) {  
    5.           askDisconnect();  
    6.       } else if (bondState == BluetoothDevice.BOND_BONDED) {  
    7.           mCachedDevice.connect(true);  
    8.       } .......  
    9.   }  
    10.   
    11.     void connect(boolean connectAllProfiles) {  
    12.       if (!ensurePaired()) {  //要先确保配对  
    13.           return;  
    14.       }  
    15.       mConnectAttempted = SystemClock.elapsedRealtime();  
    16.       connectWithoutResettingTimer(connectAllProfiles);//没别的了,只能看到这里  
    17.   }  
          代码路径这里packages/apps/Settings/src/com/android/settings/bluetooth/CachedBluetoothDevice.java,具体代码看下面
    1. // Try to initialize the profiles if they were not.  
    2.      ...........  
    3.       // Reset the only-show-one-error-dialog tracking variable  
    4.       mIsConnectingErrorPossible = true;  
    5.   
    6.       int preferredProfiles = 0;  
    7.       for (LocalBluetoothProfile profile : mProfiles) {  
    8.           if (connectAllProfiles ? profile.isConnectable() : profile.isAutoConnectable()) {  
    9.               if (profile.isPreferred(mDevice)) {  
    10.                   ++preferredProfiles;  
    11.                   connectInt(profile);//连接在这里,  
    12.               }  
    13.           }  
    14.       }  
    15.      .............  
           connectInt的实现很简单,直接跳过看里面的profile.connect(mDevice),这里的profile是指A2dpProfile,所以connet()方法的具体实现在
    1. public boolean connect(BluetoothDevice device) {  
    2.     if (mService == null) return false;  
    3.     List<BluetoothDevice> sinks = getConnectedDevices();  
    4.     if (sinks != null) {  
    5.         for (BluetoothDevice sink : sinks) {  
    6.             mService.disconnect(sink);  
    7.     }}  
    8.     return mService.connect(device);  
    9. }  
            下面是 BluetoothA2dp.java (frameworksasecorejavaandroidluetooth)  ,为什么是这样看下这个private BluetoothA2dp mService;就知道了
    1. public boolean connect(BluetoothDevice device) {  
    2.       if (mService != null && isEnabled() &&  
    3.           isValidDevice(device)) {  
    4.           try {  
    5.               return mService.connect(device);  
    6.           } catch (RemoteException e) {  
    7.               Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));  
    8.               return false;  
    9.           }  
    10.       }...........  
    11.       return false;  
    12.        
    13.       Binder跳转  
    14.       public boolean connect(BluetoothDevice device) {  
    15.           A2dpService service = getService();  
    16.           if (service == null) return false;  
    17.           return service.connect(device);  
    18.       }  
    19.        
    20.   }  
            之后的跳转和第一部分蓝牙接听电话跳转过程类似,就不重复了,最后会来到packages/apps/Bluetooth/jni/com_android_bluetooth_a2dp.cpp的connectA2dpNative,同样到下面的代码,我们能看到的开放的代码也就是这些,再下面要看vendor的具体实现了。
    1. static jboolean connectA2dpNative(JNIEnv *env, jobject object, jbyteArray address) {  
    2.   jbyte *addr;  
    3.   bt_bdaddr_t * btAddr;  
    4.   bt_status_t status;  
    5.   
    6.   ALOGI("%s: sBluetoothA2dpInterface: %p", __FUNCTION__, sBluetoothA2dpInterface);  
    7.   if (!sBluetoothA2dpInterface) return JNI_FALSE;  
    8.   
    9.   addr = env->GetByteArrayElements(address, NULL);  
    10.   btAddr = (bt_bdaddr_t *) addr;  
    11.   if (!addr) {  
    12.       jniThrowIOException(env, EINVAL);  
    13.       return JNI_FALSE;  
    14.   }  
    15.   if ((status = sBluetoothA2dpInterface->connect((bt_bdaddr_t *)addr)) != BT_STATUS_SUCCESS) {  
    16.       ALOGE("Failed HF connection, status: %d", status);  
    17.   }  
    18.   env->ReleaseByteArrayElements(address, addr, 0);  
    19.   return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;  
  • 相关阅读:
    1451. Rearrange Words in a Sentence
    1450. Number of Students Doing Homework at a Given Time
    1452. People Whose List of Favorite Companies Is Not a Subset of Another List
    1447. Simplified Fractions
    1446. Consecutive Characters
    1448. Count Good Nodes in Binary Tree
    709. To Lower Case
    211. Add and Search Word
    918. Maximum Sum Circular Subarray
    lua 时间戳和时间互转
  • 原文地址:https://www.cnblogs.com/wangzehuaw/p/3806774.html
Copyright © 2011-2022 走看看