WiredAccessoryManager(有线辅助管理器)

1 音频外设状态
要对音频外设进行管理,所以我们必须明确当前Andorid系统支持的外设设备有哪些。当前是通过一个整型变量去针对不同的音频外设进行标志与表示。任何可用的音频外设在这个整型变量中用1个二进制的标志为去表示。具体的音频表示如下:
WiredAccessoryManager(有线辅助管理器)_第1张图片
WiredAccessoryManager: newName=h2w newState=2 headsetState=2 prev headsetState=0

01-19 05:40:41.395 1036 1370 V WiredAccessoryManager: notifyWiredAccessoryChanged: when=673633706000 bits=SW_HEADPHONE_INSERT SW_MICROPHONE_INSERT mask=94
01-19 05:40:41.395 1036 1370 V WiredAccessoryManager: newName=h2w newState=1 headsetState=1 prev headsetState=0
01-19 05:40:41.396 1036 1370 I WiredAccessoryManager: MSG_NEW_DEVICE_STATE
01-19 05:40:41.396 1036 1036 V WiredAccessoryManager: headsetName: connected

WiredAccessoryManager(有线辅助管理器)_第2张图片

当前Android主要通过WiredAccessoryManager去监测音频外设的插入和拔出。WiredAccessoryManager开机的时候已经通过SystemServer.java间接启动并分配了一个自由的线程,一旦监测到有音频外设的操作,这线程就会进行处理。WiredAccessoryManager刚开始时通过WiredAccessoryObserver去处理外设消息。WiredAccessoryObserver启动的流程如下:
WiredAccessoryManager(有线辅助管理器)_第3张图片
WiredAccessoryObserver启动是蛮简单的。系统服务SystemServer通过systemRunning()启动输入管理服务InputManagerService,InputManagerService在此过程中通过callback机制

启动WiredAccessoryManager并使其去读取当前的外设状态。WiredAccessoryManager是通过WiredAccessoryObserver去管理音频外设状态的,所以最后WiredAccessoryManager启动WiredAccessoryObserver并通过startObserving()去针对每种类型的硬件启动一个线程,对当前的外设状态进行判断。

当Android连接或者断开连接设备的时候,此时底层通过Native层回掉InputManagerService的notifySwitch从而调用WiredAccessoryManager的notifyWiredAccessoryChanged()判断得出一个新的headset状态,再根据headset的状态去设置outDevice和inDevice的值,从而通过AudioManager设置状态。

/frameworks/base/services/core/java/com/android/server/WiredAccessoryManager.java

      public void notifyWiredAccessoryChanged(long whenNanos, int switchValues, int switchMask) {
123          if (LOG) Slog.v(TAG, "notifyWiredAccessoryChanged: when=" + whenNanos
124                  + " bits=" + switchCodeToString(switchValues, switchMask)
125                  + " mask=" + Integer.toHexString(switchMask));
126  
127          synchronized (mLock) {
128              int headset;
129              mSwitchValues = (mSwitchValues & ~switchMask) | switchValues;
130              switch (mSwitchValues &
131                  (SW_HEADPHONE_INSERT_BIT | SW_MICROPHONE_INSERT_BIT | SW_LINEOUT_INSERT_BIT)) {
132                  case 0:
133                      headset = 0;
134                      break;
135  
136                  case SW_HEADPHONE_INSERT_BIT:
137                      headset = BIT_HEADSET_NO_MIC;
138                      break;
139  
140                  case SW_LINEOUT_INSERT_BIT:
141                      headset = BIT_LINEOUT;
142                      break;
143  
144                  case SW_HEADPHONE_INSERT_BIT | SW_MICROPHONE_INSERT_BIT:
145                      headset = BIT_HEADSET;
146                      break;
147  
148                  case SW_MICROPHONE_INSERT_BIT:
149                      headset = BIT_HEADSET;
150                      break;
151  
152                  default:
153                      headset = 0;
154                      break;
155              }
156  
157              updateLocked(NAME_H2W,
158                  (mHeadsetState & ~(BIT_HEADSET | BIT_HEADSET_NO_MIC | BIT_LINEOUT)) | headset);
159          }
160      }

private void setDeviceStateLocked(int headset,
257              int headsetState, int prevHeadsetState, String headsetName) {
258          if ((headsetState & headset) != (prevHeadsetState & headset)) {
259              int outDevice = 0;
260              int inDevice = 0;
261              int state;
262  
263              if ((headsetState & headset) != 0) {
264                  state = 1;
265              } else {
266                  state = 0;
267              }
268  
269              if (headset == BIT_HEADSET) {
270                  outDevice = AudioManager.DEVICE_OUT_WIRED_HEADSET;
271                  inDevice = AudioManager.DEVICE_IN_WIRED_HEADSET;
272              } else if (headset == BIT_HEADSET_NO_MIC){
273                  outDevice = AudioManager.DEVICE_OUT_WIRED_HEADPHONE;
274              } else if (headset == BIT_LINEOUT){
275                  outDevice = AudioManager.DEVICE_OUT_LINE;
276              } else if (headset == BIT_USB_HEADSET_ANLG) {
277                  outDevice = AudioManager.DEVICE_OUT_ANLG_DOCK_HEADSET;
278              } else if (headset == BIT_USB_HEADSET_DGTL) {
279                  outDevice = AudioManager.DEVICE_OUT_DGTL_DOCK_HEADSET;
280              } else if (headset == BIT_HDMI_AUDIO) {
281                  outDevice = AudioManager.DEVICE_OUT_HDMI;
282              } else {
283                  Slog.e(TAG, "setDeviceState() invalid headset type: "+headset);
284                  return;
285              }
286  
287              if (LOG) {
288                  Slog.v(TAG, "headsetName: " + headsetName +
289                          (state == 1 ? " connected" : " disconnected"));
290              }
291  
292              if (outDevice != 0) {
293                mAudioManager.setWiredDeviceConnectionState(outDevice, state, "", headsetName);
294              }
295              if (inDevice != 0) {
296                mAudioManager.setWiredDeviceConnectionState(inDevice, state, "", headsetName);
297              }
298          }
299      }

常见的android的优化MIC耳机识别的方法有:
private static final int BIT_HEADSET = (1 << 1);// 0010
private static final int BIT_HEADSET_NO_MIC = (1 << 0);// 0001
其实解决的只是耳机慢插时的MIC 事件上报delay导致HEADSET出现被移除的问题。
原理就是
SW_HEADPHONE_INSERT_BIT | SW_MICROPHONE_INSERT_BIT:
headset = BIT_HEADSET;
SW_MICROPHONE_INSERT_BIT:
headset = BIT_HEADSET;
(mHeadsetState & ~(BIT_HEADSET | BIT_HEADSET_NO_MIC | BIT_LINEOUT)) | headset)
如果上次是BIT_HEADSET 这次又是BIT_HEADSET 那么是不是就正好unstall了。

从上面可以看出,真正进行音频外设管理的是AudioManager。而AudioManager是AudioService的管理。所以更多的设置在AudioService中进行。

/frameworks/base/media/java/android/media/
H A D	AudioManager.java	3300 public void setWiredDeviceConnectionState(int type, int state, String address, String name) { in setWiredDeviceConnectionState() method in AudioManager 
/frameworks/base/services/core/java/com/android/server/audio/
H A D	AudioService.java	4042 private class WiredDeviceConnectionState { class in AudioService
4049 public WiredDeviceConnectionState(int type, int state, String address, String name, in WiredDeviceConnectionState() method in AudioService.WiredDeviceConnectionState 
public void setWiredDeviceConnectionState(int type, int state, String address, String name,
4060              String caller) {
4061          synchronized (mConnectedDevices) {
4062              if (DEBUG_DEVICES) {
4063                  Slog.i(TAG, "setWiredDeviceConnectionState(" + state + " nm: " + name + " addr:"
4064                          + address + ")");
4065              }
4066              int delay = checkSendBecomingNoisyIntent(type, state);
//在这里需要去检查是否应该发送becomingNoisy的Intent。从而我们可以发现,平时我们监测拔出耳机使用的becomingNoisy是在这里开始的。
 //接下来将信息通过queueMsgUnderWakeLock交给AudioHandler去处理  
4067              queueMsgUnderWakeLock(mAudioHandler,
4068                      MSG_SET_WIRED_DEVICE_CONNECTION_STATE,
4069                      0,
4070                      0,
4071                      new WiredDeviceConnectionState(type, state, address, name, caller),
4072                      delay);
4073          }
4074      }

这里有个关于客制化的问题:
需求:拔出某些设备直接speaker播放,不暂停。

5367      // Devices which removal triggers intent ACTION_AUDIO_BECOMING_NOISY. The intent is only
5368      // sent if none of these devices is connected.
5369      // Access synchronized on mConnectedDevices
5370      int mBecomingNoisyIntentDevices =
5371              AudioSystem.DEVICE_OUT_WIRED_HEADSET | AudioSystem.DEVICE_OUT_WIRED_HEADPHONE |
5372              AudioSystem.DEVICE_OUT_ALL_A2DP | AudioSystem.DEVICE_OUT_HDMI |
5373              AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET | AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET |
5374              AudioSystem.DEVICE_OUT_ALL_USB | AudioSystem.DEVICE_OUT_LINE;
5375  
5376      // must be called before removing the device from mConnectedDevices
		//其中checkSendBecomingNoisyIntent又发个一个消息通知给到上层:
5377      // Called synchronized on mConnectedDevices
5378      private int checkSendBecomingNoisyIntent(int device, int state) {
5379          int delay = 0;
5380          if (mConnectedBTDevicesList.size() > 1) {
5381              Log.d(TAG, "checkSendBecomingNoisyIntent on state: " + state);
5382              return delay;
5383          }
5384  
5385          if ((state == 0) && ((device & mBecomingNoisyIntentDevices) != 0)) {
5386              int devices = 0;
5387              Log.d(TAG, "checkSendBecomingNoisyIntent update the noise");
5388              for (int i = 0; i < mConnectedDevices.size(); i++) {
5389                  int dev = mConnectedDevices.valueAt(i).mDeviceType;
5390                  if (((dev & AudioSystem.DEVICE_BIT_IN) == 0)
5391                          && ((dev & mBecomingNoisyIntentDevices) != 0)) {
5392                      devices |= dev;
5393                  }
5394              }
5395            if (devices == device && device != AudioSystem.DEVICE_OUT_USB_DEVICE && device !=AudioSystem.DEVICE_IN_USB_DEVICE) {
//将usb的audio设备过滤掉,不发送MSG_BROADCAST_AUDIO_BECOMING_NOISY,
5396                  sendMsg(mAudioHandler,
5397                          MSG_BROADCAST_AUDIO_BECOMING_NOISY,
5398                          SENDMSG_REPLACE,
5399                          0,
5400                          0,
5401                          null,
5402                          0);
5403                  delay = SystemProperties.getInt("audio.noisy.broadcast.delay", 700);
5404              }
5405          }
5406 
		//MSG_BROADCAST_AUDIO_BECOMING_NOISY
		//这个消息对应audiomanager中的这个类型:ACTION_AUDIO_BECOMING_NOISY
		//应用收到这个通知后会做一个暂停的处理,
5407          if (mAudioHandler.hasMessages(MSG_SET_A2DP_SRC_CONNECTION_STATE) ||
5408                  mAudioHandler.hasMessages(MSG_SET_A2DP_SINK_CONNECTION_STATE) ||
5409                  mAudioHandler.hasMessages(MSG_SET_WIRED_DEVICE_CONNECTION_STATE)) {
5410              synchronized (mLastDeviceConnectMsgTime) {
5411                  long time = SystemClock.uptimeMillis();
5412                  if (mLastDeviceConnectMsgTime > time) {
5413                      delay = (int)(mLastDeviceConnectMsgTime - time) + 30;
5414                  }
5415              }
5416          }
5417          return delay;
5418      }

第二,新建一个WiredDeviceConnectionState对象,并将这个对象通过queueMsgUnderWakeLock()交给AudioHandler去处理。并且,在此过程中,需要按照队列的形式去处理。在此期间还会获取一个mAudioEventWakeLock,当handle处理完之后会release掉。
AudioHandler接收到发给它的信息,通过判断会调用onSetWiredDeviceConnectionState()进行进一步的处理。

private void onSetWiredDeviceConnectionState(int device, int state, String address,  
            String deviceName, String caller) {  
        ……  
        synchronized (mConnectedDevices) {  
            //根据状态判断,假如当前拔下普通耳机,就会将当前音频输出到蓝牙耳机(假如有的话)  
            if ((state == 0) && ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||  
                    (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) ||  
                    (device == AudioSystem.DEVICE_OUT_LINE))) {  
                setBluetoothA2dpOnInt(true);  
            }  
            ……  
           //通过handleDeviceConnection去更新mConnectedDevices中的信息和调用AudioSystem去设置值。  
            if (!handleDeviceConnection(state == 1, device, address, deviceName)) {  
                return;  
            }  
            if (state != 0) {  
            ……  
            if (!isUsb && device != AudioSystem.DEVICE_IN_WIRED_HEADSET) {  
                //发送Intent去通知外设状态变化  
                sendDeviceConnectionIntent(device, state, address, deviceName);  
            }  
        }  
    } 

在onSetWiredDeviceConnectionState()中,其实最重要的就是进行2个操作:handleDeviceConnection()和sendDeviceConnectionIntent()。这两个操作一个负责对mConnectedDevices更新并通过AudioSystem去设置值进底层。一个发送Intent去通知音频外设的状态变化。所以,我们关注的重点应该是handleDeviceConnection()。

5330      private boolean handleDeviceConnection(boolean connect, int device, String address,
5331              String deviceName) {
5332          if (DEBUG_DEVICES) {
5333              Slog.i(TAG, "handleDeviceConnection(" + connect + " dev:" + Integer.toHexString(device)
5334                      + " address:" + address + " name:" + deviceName + ")");
5335          }
5336          synchronized (mConnectedDevices) {
5337              String deviceKey = makeDeviceListKey(device, address);
5338              if (DEBUG_DEVICES) {
5339                  Slog.i(TAG, "deviceKey:" + deviceKey);
5340              }
5341              DeviceListSpec deviceSpec = mConnectedDevices.get(deviceKey);
5342              boolean isConnected = deviceSpec != null;
5343              if (DEBUG_DEVICES) {
5344                  Slog.i(TAG, "deviceSpec:" + deviceSpec + " is(already)Connected:" + isConnected);
5345              }
5346              if (connect && !isConnected) {
5347                  final int res = AudioSystem.setDeviceConnectionState(device,
5348                          AudioSystem.DEVICE_STATE_AVAILABLE, address, deviceName);
5349                  if (res != AudioSystem.AUDIO_STATUS_OK) {
5350                      Slog.e(TAG, "not connecting device 0x" + Integer.toHexString(device) +
5351                              " due to command error " + res );
5352                      return false;
5353                  }
5354                  mConnectedDevices.put(deviceKey, new DeviceListSpec(device, deviceName, address));
5355                  return true;
5356              } else if (!connect && isConnected) {
5357                  AudioSystem.setDeviceConnectionState(device,
5358                          AudioSystem.DEVICE_STATE_UNAVAILABLE, address, deviceName);
5359                  // always remove even if disconnection failed
5360                  mConnectedDevices.remove(deviceKey);
5361                  return true;
5362              }
5363          }
5364          return false;
5365      }

从上面我们可以看出,handleDeviceConnection()负责处理设备的连接和断开连接。他会将设备的信息更新,并通过AudioSystem设置进底层。
WiredAccessoryManager(有线辅助管理器)_第4张图片
总结一下音频外设的拨插处理过程:
1) InputManagerService监听到从底层的上报的设备状态变化消息。通过WiredAccessoryManager去处理。
2) WiredAccessoryManager判断状态并将状态变化交给AudioService处理。
3) AudioService得到通知,根据需要判断是否发送BECOMING_NOISY相关Intent,并新列表。
4) AudioService将处理后的状态变化通过AudioSystem交给底层去处理。
。。。。。。AudioSystem.setDeviceConnectionState

你可能感兴趣的:(android)