Platform: Rockchip
OS: Android 6.0
Kernel: 3.10.92
WiredAccessoryObserver用来处理kernel通知耳机插拔事件,不够它只监听有线音频外设连接,其他无线的耳机在其他模块维护。
WiredAccessoryObserver继承自UEventObserver, UEventObserver用于接收Uevent的一个类,内部维护一个线程,用于接收UEvent事件,通过调用它的StartObserving()来告诉UEventObserver要监听什么样的UEvent,当事件到来的时候会调用对应的onUEvent()来处理。
初始化一:
WiredAccessoryObserver接收audio jack/hdmi audio/usb audio这三个事件.
每种外设会被定义成一个UEventInfo用于保存它的状态。
WiredAccessoryManager.java:
private List makeObservedUEventList() {
List retVal = new ArrayList();
UEventInfo uei;
//audio jack事件注册
// Monitor h2w
if (!mUseDevInputEventForAudioJack) {
uei = new UEventInfo(NAME_H2W, BIT_HEADSET, BIT_HEADSET_NO_MIC, BIT_LINEOUT);
if (uei.checkSwitchExists()) {
retVal.add(uei);
} else {
Slog.w(TAG, "This kernel does not have wired headset support");
}
}
//usb audio事件注册
// Monitor USB
uei = new UEventInfo(NAME_USB_AUDIO, BIT_USB_HEADSET_ANLG, BIT_USB_HEADSET_DGTL, 0);
if (uei.checkSwitchExists()) {
retVal.add(uei);
} else {
Slog.w(TAG, "This kernel does not have usb audio support");
}
//HDMI audio事件注册
// Monitor HDMI
uei = new UEventInfo(NAME_HDMI_AUDIO, BIT_HDMI_AUDIO, 0, 0);
if (uei.checkSwitchExists()) {
retVal.add(uei);
} else {
uei = new UEventInfo(NAME_HDMI, BIT_HDMI_AUDIO, 0, 0);
if (uei.checkSwitchExists()) {
retVal.add(uei);
} else {
Slog.w(TAG, "This kernel does not have HDMI audio support");
}
}
return retVal;
}
初始化二:
对前面的外设进行状态初始化。
WiredAccessoryManager.java:
void init() {
synchronized (mLock) {
for (int i = 0; i < mUEventInfo.size(); ++i) {
UEventInfo uei = mUEventInfo.get(i);
try {
int curState;
//打开状态文件, mDevName在之前注册的时候有赋值。
//public String getSwitchStatePath() {
// return String.format(Locale.US, "/sys/class/switch/%s/state", mDevName);
//}
//假设这里是jack audio,那么路径就是 “/sys/class/switch/h2w/state”
FileReader file = new FileReader(uei.getSwitchStatePath());
int len = file.read(buffer, 0, 1024);
file.close();
//如果当前值为非0,表示默认开机的时候就有耳机插入。
curState = Integer.valueOf((new String(buffer, 0, len)).trim());
//有设备插入就要做处理,这里假设开机没有设备插入,后面事件处理再展开。
if (curState > 0) {
updateStateLocked(uei.getDevPath(), uei.getDevName(), curState);
}
}
}
}
for (int i = 0; i < mUEventInfo.size(); ++i) {
UEventInfo uei = mUEventInfo.get(i);
//注册到UEventObserver中监听对应事件。
startObserving("DEVPATH="+uei.getDevPath());
}
}
getDevPath():
public String getDevPath() {
return String.format(Locale.US, "/devices/virtual/switch/%s", mDevName);
}
耳机对应路径:
耳机插拔处理:
事件处理会触发onUEvent()调用。
public void onUEvent(UEventObserver.UEvent event) {
try {
//DEVPATH: /sys/devices/virtual/switch/h2w
String devPath = event.get("DEVPATH");
//SWITCH_NAME: 其实就是mUEventInfo中的mDevName,即“h2w”
String name = event.get("SWITCH_NAME");
//SWITCH_STATE:插入为1,拔出为0
int state = Integer.parseInt(event.get("SWITCH_STATE"));
synchronized (mLock) {
//更新状态
updateStateLocked(devPath, name, state);
}
}
}
updateStateLocked():
private void updateStateLocked(String devPath, String name, int state) {
for (int i = 0; i < mUEventInfo.size(); ++i) {
UEventInfo uei = mUEventInfo.get(i);
//找到对应发生状态变化的外设
if (devPath.equals(uei.getDevPath())) {
//获取/sys/devices/virtual/switch/h2w下的state值
updateLocked(name, uei.computeNewHeadsetState(mHeadsetState, state));
return;
}
}
}
updateLocked()对传入的state进行检查
private void updateLocked(String newName, int newState) {
// Retain only relevant bits
//SUPPORTED_HEADSETS可以控制当前系统支持的音频外设,比如不想支持hdmi audio,
//就将SUPPORTED_HEADSETS中的BIT_HDMI_AUDIO位拿掉就可以了。
int headsetState = newState & SUPPORTED_HEADSETS;
int usb_headset_anlg = headsetState & BIT_USB_HEADSET_ANLG;
int usb_headset_dgtl = headsetState & BIT_USB_HEADSET_DGTL;
int h2w_headset = headsetState & (BIT_HEADSET | BIT_HEADSET_NO_MIC | BIT_LINEOUT);
boolean h2wStateChange = true;
//状态和上次一样没变化就不处理了。
if (mHeadsetState == headsetState) {
Log.e(TAG, "No state change.");
return;
}
//发送消息事件待处理
Message msg = mHandler.obtainMessage(MSG_NEW_DEVICE_STATE, headsetState,
mHeadsetState, "");
mHandler.sendMessage(msg);
//保存当前状态
mHeadsetState = headsetState;
}
handleMessage -> setDevicesState -> setDeviceStateLocked
private void setDeviceStateLocked(int headset, int headsetState, int prevHeadsetState, String headsetName) {
//转换成audio模块的的外设编号
if (headset == BIT_HEADSET) {
outDevice = AudioManager.DEVICE_OUT_WIRED_HEADSET;
inDevice = AudioManager.DEVICE_IN_WIRED_HEADSET;
} else if (headset == BIT_HEADSET_NO_MIC){
outDevice = AudioManager.DEVICE_OUT_WIRED_HEADPHONE;
} else if (headset == BIT_LINEOUT){
outDevice = AudioManager.DEVICE_OUT_LINE;
}
//通知audioservice处理设置到audio device
mAudioManager.setWiredDeviceConnectionState(outDevice, state, "", headsetName);
}
参考: