赞
踩
- // frameworks/base/media/java/android/media/AudioManager.java
- public void startBluetoothSco(){
- service.startBluetoothSco(mICallBack,
- getContext().getApplicationInfo().targetSdkVersion);
- }
-
- // frameworks/base/services/core/java/com/android/server/audio/AudioService.java
- public void startBluetoothSco(IBinder cb, int targetSdkVersion) {
- final int scoAudioMode =
- (targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR2) ?
- BtHelper.SCO_MODE_VIRTUAL_CALL : BtHelper.SCO_MODE_UNDEFINED;
- final String eventSource = new StringBuilder("startBluetoothSco()")
- .append(") from u/pid:").append(uid).append("/")
- .append(pid).toString();
- startBluetoothScoInt(cb, uid, pid, scoAudioMode, eventSource);
- }
-
- void startBluetoothScoInt(IBinder cb, int uid, int pid, int scoAudioMode, @NonNull String eventSource) {
- final long ident = Binder.clearCallingIdentity();
- mDeviceBroker.startBluetoothScoForClient(cb, uid, pid, scoAudioMode, eventSource);
- Binder.restoreCallingIdentity(ident);
- mmi.record();
- }
-
- // frameworks/base/services/core/java/com/android/server/audio/AudioDeviceBroker.java
- void startBluetoothScoForClient(IBinder cb, int uid, int pid, int scoAudioMode, @NonNull String eventSource) {
- AudioDeviceAttributes device = new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_BLUETOOTH_SCO, "");
- setCommunicationRouteForClient(cb, uid, pid, device, scoAudioMode, eventSource);
- }
-
- void setCommunicationRouteForClient(IBinder cb, int uid, int pid, AudioDeviceAttributes device, int scoAudioMode, String eventSource) {
- ......
- mBtHelper.startBluetoothSco(scoAudioMode, eventSource);
- ......
- }
-
- // frameworks/base/services/core/java/com/android/server/audio/BtHelper.java
- synchronized boolean startBluetoothSco(int scoAudioMode, @NonNull String eventSource) {
- AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent(eventSource));
- return requestScoState(BluetoothHeadset.STATE_AUDIO_CONNECTED, scoAudioMode);
- }
-
- private boolean requestScoState(int state, int scoAudioMode) {
- if (state == BluetoothHeadset.STATE_AUDIO_CONNECTED) {
- broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTING);
- connectBluetoothScoAudioHelper(mBluetoothHeadset, mBluetoothHeadsetDevice, mScoAudioMode)
- ......
- }
- // 断开连接的时候发送断连的广播
- }
这里做了两件事,一个是发送广播,一个是调用connectBluetoothScoAudioHelper
先看广播发送
- private void broadcastScoConnectionState(int state) {
- mDeviceBroker.postBroadcastScoConnectionState(state);
- }
-
- // frameworks/base/services/core/java/com/android/server/audio/AudioDeviceBroker.java
- void postBroadcastScoConnectionState(int state) {
- sendIMsgNoDelay(MSG_I_BROADCAST_BT_CONNECTION_STATE, SENDMSG_QUEUE, state);
- }
-
- // 收到消息MSG_I_BROADCAST_BT_CONNECTION_STATE之后调用onBroadcastScoConnectionState
-
- // frameworks/base/services/core/java/com/android/server/audio/BtHelper.java
- synchronized void onBroadcastScoConnectionState(int state) {
- Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED);
- newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, state);
- newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_PREVIOUS_STATE,
- mScoConnectionState);
- sendStickyBroadcastToAll(newIntent);
- mScoConnectionState = state;
- }
-
- private void sendStickyBroadcastToAll(Intent intent) {
- mDeviceBroker.getContext().sendStickyBroadcastAsUser(intent, UserHandle.ALL);
- }
- // 最终这个广播发出去就被一个app接收去显示蓝牙俩呢及状态了。
再看connectBluetoothScoAudioHelper
- // frameworks/base/services/core/java/com/android/server/audio/BtHelper.java
- private static boolean connectBluetoothScoAudioHelper(BluetoothHeadset bluetoothHeadset, BluetoothDevice device, int scoAudioMode) {
- switch (scoAudioMode) {
- case SCO_MODE_RAW:
- return bluetoothHeadset.connectAudio();
- case SCO_MODE_VIRTUAL_CALL:
- return bluetoothHeadset.startScoUsingVirtualVoiceCall();
- case SCO_MODE_VR:
- return bluetoothHeadset.startVoiceRecognition(device);
- default:
- return false;
- }
- }
- // 这里也是各种client server交互,最终调用如下
- // packages/apps/Bluetooth/src/com/android/bluetooth/hfp/HeadsetService.java
- boolean connectAudio(BluetoothDevice device) {
- final HeadsetStateMachine stateMachine = mStateMachines.get(device);
- stateMachine.sendMessage(HeadsetStateMachine.CONNECT_AUDIO, device);
- return true;
- }
-
- // packages/apps/Bluetooth/src/com/android/bluetooth/hfp/HeadsetStateMachine.java
- public boolean processMessage(Message message) {
- case CONNECT_AUDIO:
- mSystemInterface.getAudioManager().setParameters("A2dpSuspended=true"); // 先把A2dpSuspended设置成true
- broadcastAudioState(mDevice, BluetoothHeadset.STATE_AUDIO_DISCONNECTED, BluetoothHeadset.STATE_AUDIO_DISCONNECTED);
- transitionTo(mAudioConnecting);
- }
-
- /**
- * A Bluetooth Handset StateMachine
- * (Disconnected)
- * | ^
- * CONNECT | | DISCONNECTED
- * V |
- * (Connecting) (Disconnecting)
- * | ^
- * CONNECTED | | DISCONNECT
- * V |
- * (Connected)
- * | ^
- * CONNECT_AUDIO | | AUDIO_DISCONNECTED
- * V |
- * (AudioConnecting) (AudioDiconnecting)
- * | ^
- * AUDIO_CONNECTED | | DISCONNECT_AUDIO
- * V |
- * (AudioOn)
- */
-
- // 接下来蓝牙就回进入audioon状态,进入audioon状态就会调用audio的setBluetoothScoOn
- (蓝牙app默认走高通的逻辑)
- class AudioOn extends ConnectedBase {
- public void enter() {
- ......
- mSystemInterface.getAudioManager().setBluetoothScoOn(true);
- ......
- }
- }
这里需要注意,在蓝牙进入audio on 之前就已经先把a2dpsuspended设置成了true,先让a2dp停止,然后再进入audio on,然后再设置audio的setBluetoothScoOn。
接来下看看setBluetoothScoOn的处理:
- 蓝牙进入audioon模式就会调用mSystemInterface.getAudioManager().setBluetoothScoOn(true);
- // frameworks/base/services/core/java/com/android/server/audio/AudioDeviceBroker.java
- void setBluetoothScoOn(boolean on, String eventSource) {
- synchronized (mDeviceStateLock) {
- mBluetoothScoOn = on; // 这个标记在选择device的时候使用,如果是on就会选择sco设备
- sendLMsgNoDelay(MSG_L_UPDATE_COMMUNICATION_ROUTE, SENDMSG_QUEUE, eventSource); // 这里就是更新route,选择设备
- }
- }
-
- // 收到MSG_L_UPDATE_COMMUNICATION_ROUTE信息之后就会调用onUpdateCommunicationRoute
- private void onUpdateCommunicationRoute(String eventSource) {
- AudioDeviceAttributes preferredCommunicationDevice = preferredCommunicationDevice(); // 这里选择设备
- if (preferredCommunicationDevice == null || preferredCommunicationDevice.getType() != AudioDeviceInfo.TYPE_BLUETOOTH_SCO) {
- AudioSystem.setParameters("BT_SCO=off");
- } else {
- AudioSystem.setParameters("BT_SCO=on");
- }
- postSetPreferredDevicesForStrategy(mCommunicationStrategyId, Arrays.asList(preferredCommunicationDevice));
- }
-
- private AudioDeviceAttributes preferredCommunicationDevice() {
- boolean btSCoOn = mBluetoothScoOn && mBtHelper.isBluetoothScoOn();
- if (btSCoOn) {
- AudioDeviceAttributes device = mBtHelper.getHeadsetAudioDevice();
- return device;
- }
- AudioDeviceAttributes device = requestedCommunicationDevice();
- return device;
- }
setBluetoothScoOn的作用就是: 1. 选择到sco device 2. 设置参数"BT_SCO=on"
从目前的调用逻辑来看,在蓝牙app进入audioon状态之前就设置了A2dpSuspended=true,在蓝牙进入audioon之后告诉audio sco on 的时候audio侧设置了BT_SCO=on,所以这两个的先后顺序就是先设置"A2dpSuspended=true"再设置"BT_SCO=on"。
先看看设置"A2dpSuspended=true"
- // vendor/qcom/opensource/audio-hal/primary-hal/hal/AudioDevice.cpp
- int AudioDevice::SetParameters(const char *kvpairs) {
- ret = str_parms_get_str(parms, "A2dpSuspended" , value, sizeof(value));
- if (ret >= 0) {
- pal_param_bta2dp_t param_bt_a2dp;
-
- if (strncmp(value, "true", 4) == 0)
- param_bt_a2dp.a2dp_suspended = true;
- else
- param_bt_a2dp.a2dp_suspended = false;
-
- ret = pal_set_param(PAL_PARAM_ID_BT_A2DP_SUSPENDED /* PAL_PARAM_ID_BT_A2DP_SUSPENDED = 16*/, (void *)¶m_bt_a2dp, sizeof(pal_param_bta2dp_t));
- }
- }
-
- pal_set_param 调用ResourceManager::setParameter -----> a2dp_dev->setDeviceParameter ---> rm->a2dpSuspend(); // 当suspend是true就调用rm->a2dpSuspend(), 是false就是rm->a2dpResume()
设置"BT_SCO=on"
- // vendor/qcom/opensource/audio-hal/primary-hal/hal/AudioDevice.cpp
- int AudioDevice::SetParameters(const char *kvpairs) {
- ret = str_parms_get_str(parms, "BT_SCO", value, sizeof(value));
- if (ret >= 0) {
- pal_param_btsco_t param_bt_sco;
- if (strcmp(value, AUDIO_PARAMETER_VALUE_ON) == 0) {
- param_bt_sco.bt_sco_on = true;
- } else {
- param_bt_sco.bt_sco_on = false;
- }
- ret = pal_set_param(PAL_PARAM_ID_BT_SCO/*PAL_PARAM_ID_BT_SCO = 11*/, (void *)¶m_bt_sco, sizeof(pal_param_btsco_t));
- }
- }
-
- pal_set_param 调用ResourceManager::setParameter
- // vendor/qcom/opensource/pal/resource_manager/src/ResourceManager.cpp
- int ResourceManager::setParameter(uint32_t param_id, void *param_payload, size_t payload_size) {
- case PAL_PARAM_ID_BT_SCO: {
- struct pal_device dattr;
- dattr.id = PAL_DEVICE_OUT_BLUETOOTH_SCO;
- dev = Device::getInstance(&dattr, rm); // 获取sco device
-
- param_bt_sco = (pal_param_btsco_t*)param_payload;
- status = dev->setDeviceParameter(param_id, param_payload);
- // 下面就是一些设备切换的逻辑
- std::vector <std::shared_ptr<Device>> rxDevices;
- std::vector <std::shared_ptr<Device>> txDevices;
- if (param_bt_sco->bt_sco_on == true) {
- for (auto& str : mActiveStreams) { // 循环处理所有stream
- str->getStreamAttributes(&sAttr);
- // 根据sAttr的type判断是否是rx且是需要切换到sco的stream如果是
- if(上面的条件满足) {
- str->getAssociatedDevices(associatedDevices);
- for (int i = 0; i < associatedDevices.size(); i++) {
- dAttr.id = (pal_device_id_t)associatedDevices[i]->getSndDeviceId();
- dev = Device::getInstance(&dAttr, rm);
- if (dev && (!isBtScoDevice(dAttr.id)) && (dAttr.id != PAL_DEVICE_OUT_PROXY) && isDeviceAvailable(PAL_DEVICE_OUT_BLUETOOTH_SCO)) {
- rxDevices.push_back(dev); // 把device放入需要切换的列表中
- 7823 }
- }
- } else if(如果是tx,且是需要切换到sco的stream) {
- 同上的方法,把需要切换到device放入txDevices列表中
- }
- }
- }
-
- sco_rx_dattr.id = PAL_DEVICE_OUT_BLUETOOTH_SCO;
- status = getDeviceConfig(&sco_rx_dattr, NULL);
-
- sco_tx_dattr.id = PAL_DEVICE_IN_BLUETOOTH_SCO_HEADSET;
- status = getDeviceConfig(&sco_tx_dattr, NULL);
-
- SortAndUnique(rxDevices);
- SortAndUnique(txDevices);
- for (auto& device : rxDevices) {
- rm->forceDeviceSwitch(device, &sco_rx_dattr);
- }
- for (auto& device : txDevices) {
- rm->forceDeviceSwitch(device, &sco_tx_dattr);
- }
- }
- }
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。