Android 8 蓝牙 A2DP流程

记录一下蓝牙A2DP的流程



packages\apps\Settings\src\com\android\settings\bluetooth\BluetoothPairingDetail.java
    @Override
    void onDevicePreferenceClick(BluetoothDevicePreference btPreference) {
        disableScanning();
        super.onDevicePreferenceClick(btPreference);
    }   
    
packages\apps\Settings\src\com\android\settings\bluetooth\DeviceListPreferenceFragment.java
    void onDevicePreferenceClick(BluetoothDevicePreference btPreference) {
        btPreference.onClicked();
    }
        
packages\apps\Settings\src\com\android\settings\bluetooth\BluetoothDevicePreference.java
    void onClicked() {
        Context context = getContext();
        // 获取连接状态
        int bondState = mCachedDevice.getBondState();

        final MetricsFeatureProvider metricsFeatureProvider =
                FeatureFactory.getFactory(context).getMetricsFeatureProvider();
        // 已经连接
        if (mCachedDevice.isConnected()) {
            // 断开连接
            metricsFeatureProvider.action(context,
                    MetricsEvent.ACTION_SETTINGS_BLUETOOTH_DISCONNECT);
            askDisconnect();
            // 以前连接过,不需要再配对,直接进行连接
        } else if (bondState == BluetoothDevice.BOND_BONDED) {
            metricsFeatureProvider.action(context,
                    MetricsEvent.ACTION_SETTINGS_BLUETOOTH_CONNECT);
            mCachedDevice.connect(true);
            // 没连接过,进行配对,需要连接的双方都同意之后才能连接
        } else if (bondState == BluetoothDevice.BOND_NONE) {
            metricsFeatureProvider.action(context,
                    MetricsEvent.ACTION_SETTINGS_BLUETOOTH_PAIR);
            if (!mCachedDevice.hasHumanReadableName()) {
                metricsFeatureProvider.action(context,
                        MetricsEvent.ACTION_SETTINGS_BLUETOOTH_PAIR_DEVICES_WITHOUT_NAMES);
            }
            pair();
        }
    }
    
    

匹配过的设备,进行连接
    frameworks\base\packages\SettingsLib\src\com\android\settingslib\bluetooth\CachedBluetoothDevice.java
        public void connect(boolean connectAllProfiles) {
        // 是否配对过
        if (!ensurePaired()) {
            return;
        }

        mConnectAttempted = SystemClock.elapsedRealtime();
        connectWithoutResettingTimer(connectAllProfiles);
    }
    
        private void connectWithoutResettingTimer(boolean connectAllProfiles) {
        // Try to initialize the profiles if they were not.
        if (mProfiles.isEmpty()) {
            // if mProfiles is empty, then do not invoke updateProfiles. This causes a race
            // condition with carkits during pairing, wherein RemoteDevice.UUIDs have been updated
            // from bluetooth stack but ACTION.uuid is not sent yet.
            // Eventually ACTION.uuid will be received which shall trigger the connection of the
            // various profiles
            // If UUIDs are not available yet, connect will be happen
            // upon arrival of the ACTION_UUID intent.
            Log.d(TAG, "No profiles. Maybe we will connect later");
            return;
        }

        // Reset the only-show-one-error-dialog tracking variable
        mIsConnectingErrorPossible = true;

        int preferredProfiles = 0;
        for (LocalBluetoothProfile profile : mProfiles) {
            // connectAllProfile传进来的是true
            if (connectAllProfiles ? profile.isConnectable() : profile.isAutoConnectable()) {
                if (profile.isPreferred(mDevice)) {
                    ++preferredProfiles;
                    connectInt(profile);            // 选择对应的profile进行连接
                }
            }
        }
        if (DEBUG) Log.d(TAG, "Preferred profiles = " + preferredProfiles);

        if (preferredProfiles == 0) {
            connectAutoConnectableProfiles();
        }
    }

    private void connectAutoConnectableProfiles() {
        if (!ensurePaired()) {
            return;
        }
        // Reset the only-show-one-error-dialog tracking variable
        mIsConnectingErrorPossible = true;

        for (LocalBluetoothProfile profile : mProfiles) {
            if (profile.isAutoConnectable()) {
                profile.setPreferred(mDevice, true);
                connectInt(profile);
            }
        }
    }
    
frameworks\base\packages\SettingsLib\src\com\android\settingslib\bluetooth\CachedBluetoothDevice.java
        synchronized void connectInt(LocalBluetoothProfile profile) {
        // 判断是否配对过
        if (!ensurePaired()) {
            return;
        }
        // 连接
        if (profile.connect(mDevice)) {
            if (Utils.D) {
                Log.d(TAG, "Command sent successfully:CONNECT " + describe(profile));
            }
            return;
        }
        Log.i(TAG, "Failed to connect " + profile.toString() + " to " + mName);
    }
    

A2dp的profile    
frameworks\base\packages\SettingsLib\src\com\android\settingslib\bluetooth\A2dpProfile.java
public class A2dpProfile implements LocalBluetoothProfile {

    public boolean connect(BluetoothDevice device) {
        if (mService == null) return false;
        List<BluetoothDevice> sinks = getConnectedDevices();
        if (sinks != null) {
            for (BluetoothDevice sink : sinks) {
                if (sink.equals(device)) {
                    Log.w(TAG, "Connecting to device " + device + " : disconnect skipped");
                    continue;
                }
            }
        }
        // 连接
        return mService.connect(device);
    }
    
    
frameworks\base\core\java\android\bluetooth\BluetoothA2dp.java
     @GuardedBy("mServiceLock") private IBluetoothA2dp mService;
     
    public boolean connect(BluetoothDevice device) {
        if (DBG) log("connect(" + device + ")");
        try {
            mServiceLock.readLock().lock();
            if (mService != null && isEnabled() &&
                isValidDevice(device)) {
                return mService.connect(device);    // 调用aidl中的方法
            }
            if (mService == null) Log.w(TAG, "Proxy not attached to service");
            return false;
        } catch (RemoteException e) {
            Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
            return false;
        } finally {
            mServiceLock.readLock().unlock();
        }
    }
    
    
    
Binder进程间通信,服务端实现方法如下。  
packages\apps\Bluetooth\src\com\android\bluetooth\a2dp\A2dpService.java
    private static class BluetoothA2dpBinder extends IBluetoothA2dp.Stub 
    implements IProfileServiceBinder {
        
            public boolean connect(BluetoothDevice device) {
            A2dpService service = getService();
            if (service == null) return false;
            //do not allow new connections with active multicast
            if (service.isMulticastOngoing(device)) {
                Log.i(TAG,"A2dp Multicast is Ongoing, ignore Connection Request");
                return false;
            }
            return service.connect(device);
        }


    public boolean connect(BluetoothDevice device) {
        if (DBG) Log.d(TAG, "Enter connect");
        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
                                       "Need BLUETOOTH ADMIN permission");

        if (getPriority(device) == BluetoothProfile.PRIORITY_OFF) {
            return false;
        }
        ParcelUuid[] featureUuids = device.getUuids();
        if ((BluetoothUuid.containsAnyUuid(featureUuids, A2DP_SOURCE_UUID)) &&
            !(BluetoothUuid.containsAllUuids(featureUuids ,A2DP_SOURCE_SINK_UUIDS))) {
            Log.e(TAG,"Remote does not have A2dp Sink UUID");
            return false;
        }

        int connectionState = BluetoothProfile.STATE_DISCONNECTED;
        synchronized(mBtA2dpLock) {
            if (mStateMachine != null) {
                connectionState = mStateMachine.getConnectionState(device);
            }
        }
        if (connectionState == BluetoothProfile.STATE_CONNECTED ||
            connectionState == BluetoothProfile.STATE_CONNECTING) {
            return false;
        }
        // 发送消息给状态机
        synchronized(mBtA2dpLock) {
            if (mStateMachine != null) {
                mStateMachine.sendMessage(A2dpStateMachine.CONNECT, device);
            }
        }
        if (DBG) Log.d(TAG, "Exit connect");
        return true;
    }       
    
    
    状态机初始状态Disconnect
packages\apps\Bluetooth\src\com\android\bluetooth\a2dp\A2dpStateMachine.java
final class A2dpStateMachine extends StateMachine {
    
    
               switch(message.what) {
                case CONNECT:
                    BluetoothDevice device = (BluetoothDevice) message.obj;
                    // 发送广播,状态改变
                    broadcastConnectionState(device, BluetoothProfile.STATE_CONNECTING,
                                   BluetoothProfile.STATE_DISCONNECTED);
                    // 进行连接
                    if (!connectA2dpNative(getByteAddress(device)) ) {
                        // 连接完成,失败就再次发广播,状态有connecting->disconnect 
                        broadcastConnectionState(device, BluetoothProfile.STATE_DISCONNECTED,
                                       BluetoothProfile.STATE_CONNECTING);
                        break;
                    }

                    synchronized (A2dpStateMachine.this) {
                        mTargetDevice = device;
                        transitionTo(mPending);         // 切换状态机状态
                    }
                    // TODO(BT) remove CONNECT_TIMEOUT when the stack
                    //          sends back events consistently
                    Message m = obtainMessage(CONNECT_TIMEOUT);
                    m.obj = device;
                    sendMessageDelayed(m, CONNECT_TIMEOUT_SEC);
                    break;
                    
                    
packages\apps\Bluetooth\jni\com_android_bluetooth_a2dp.cpp
static jboolean connectA2dpNative(JNIEnv* env, jobject object,
                                  jbyteArray address) {
  ALOGI("%s: sBluetoothA2dpInterface: %p", __func__, sBluetoothA2dpInterface);
  if (!sBluetoothA2dpInterface) return JNI_FALSE;

  jbyte* addr = env->GetByteArrayElements(address, NULL);
  if (!addr) {
    jniThrowIOException(env, EINVAL);
    return JNI_FALSE;
  }

  bt_status_t status = sBluetoothA2dpInterface->connect((RawAddress*)addr);
  if (status != BT_STATUS_SUCCESS) {
    ALOGE("Failed HF connection, status: %d", status);
  }
  env->ReleaseByteArrayElements(address, addr, 0);
  return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
}

初始化
static void initNative(JNIEnv* env, jobject object,
                       jobjectArray codecConfigArray,
                       jint maxA2dpConnection,
                       jint multiCastState) {
                       
 sBluetoothA2dpInterface =
      (btav_source_interface_t*)btInf->get_profile_interface(
          BT_PROFILE_ADVANCED_AUDIO_ID);
  if (sBluetoothA2dpInterface == NULL) {
    ALOGE("Failed to get Bluetooth A2DP Interface");
    return;
  }
  
  
  
  Z:\eda51\system\bt\btif\src\bluetooth.cc
  static const void* get_profile_interface(const char* profile_id) {
  LOG_INFO(LOG_TAG, "%s: id = %s", __func__, profile_id);

  /* sanity check */
  if (interface_ready() == false) return NULL;

  /* check for supported profile interfaces */
  if (is_profile(profile_id, BT_PROFILE_HANDSFREE_ID))
    return btif_hf_get_interface();

  if (is_profile(profile_id, BT_PROFILE_HANDSFREE_CLIENT_ID))
    return btif_hf_client_get_interface();

  if (is_profile(profile_id, BT_PROFILE_SOCKETS_ID))
    return btif_sock_get_interface();

  if (is_profile(profile_id, BT_PROFILE_PAN_ID))
    return btif_pan_get_interface();
    // audio有两个,一个是作为source用
  if (is_profile(profile_id, BT_PROFILE_ADVANCED_AUDIO_ID))
    return btif_av_get_src_interface();
    // audio, 作为sink用
  if (is_profile(profile_id, BT_PROFILE_ADVANCED_AUDIO_SINK_ID))
    return btif_av_get_sink_interface();
    
    
    
system\bt\btif\src\btif_av.cc
const btav_source_interface_t* btif_av_get_src_interface(void) {
  BTIF_TRACE_EVENT("%s", __func__);
  return &bt_av_src_interface;
}

static const btav_source_interface_t bt_av_src_interface = {
    sizeof(btav_source_interface_t),
    init_src,
    src_connect_sink,   // 音频源连接sink,这个应该是对音频进行编码,然后输出
    disconnect,
    codec_config_src,
    cleanup_src,
    allow_connection,
    select_audio_device,
};

static const btav_sink_interface_t bt_av_sink_interface = {
    sizeof(btav_sink_interface_t),
    init_sink,
    sink_connect_src,   // sink连接音频源, sink接受音频数据,解码进行播放
    disconnect,
    cleanup_sink,
    update_audio_focus_state,
    update_audio_track_gain,
};

Liu Tao
2019-3-28

Android 8 蓝牙 A2DP流程

上一篇:基于vue-cli的vue项目移动端样式适配,lib-flexible和postcss-px2rem


下一篇:CSS 按钮 - Break易站