Audio笔记之耳机插拔检测

System Server是Android系统的核心,他在Dalvik虚拟机启动后立即开始初始化和运行。其它的系统服务在System Server进程的环境中运行。

在main函数中,首先检查系统时间设置和SamplingProfiler。然后加载一个叫android_servers的本地库,他提供本地方法的接口(源程序在framework/base/services/jni/目录中)。

然后调用本地方法设置服务。然后执行一个死循环线程,该线程中启动了很多服务。

   public static void main(String[] args) {

        ... ...

        Environment.setUserRequired(true);

        System.loadLibrary("android_servers");

        Slog.i(TAG, "Entered the Android system server!");

        // Initialize native services.

        nativeInit();

        // This used to be its own separate thread, but now it is

        // just the loop we run on the main thread.

        ServerThread thr = new ServerThread();

        thr.initAndLoop();

    }
}

在ServerThread中启动了监听有线耳机接入的服务。

            if (!disableMedia) {

                try {

                    Slog.i(TAG, "Wired Accessory Manager");

                    // Listen for wired headset changes

                    inputManager.setWiredAccessoryCallbacks(

                            new WiredAccessoryManager(context, inputManager));

                } catch (Throwable e) {

                    reportWtf("starting WiredAccessoryManager", e);

                }

            }
在base/services/java/com/android/server/WiredAccessoryManager.java中
WiredAccessoryManager中使用了两种方式监听耳机的状态
在构造函数中获得mUseDevInputEventForAudioJack的状态,配置为false。

public WiredAccessoryManager(Context context, InputManagerService inputManager) {

  PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);

  mWakeLock = pm.newWakeLock(

              PowerManager.PARTIAL_WAKE_LOCK, "WiredAccessoryManager");

        mWakeLock.setReferenceCounted(false);

        mAudioManager = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE);

        mInputManager = inputManager;

        mContext= context;  

        mUseDevInputEventForAudioJack =

        context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);
        //构造监听耳机状态的对象
        mObserver = new WiredAccessoryObserver();

        context.registerReceiver(new BroadcastReceiver() {

                    @Override

                    public void onReceive(Context ctx, Intent intent) {

                        bootCompleted();

                    }

                },

                new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null);

    }
在启动完成后就开启监听,注册了开机广播,开机后,会开始所有相关的UEvent,并且开始监听。在private void bootCompleted()中

    private void bootCompleted() {
        if (mUseDevInputEventForAudioJack) {
            int switchValues = 0;
            if (mInputManager.getSwitchState(-1, InputDevice.SOURCE_ANY, SW_HEADPHONE_INSERT) == 1) {
                switchValues |= SW_HEADPHONE_INSERT_BIT;
            }
            if (mInputManager.getSwitchState(-1, InputDevice.SOURCE_ANY, SW_MICROPHONE_INSERT) == 1) {
                switchValues |= SW_MICROPHONE_INSERT_BIT;
            }
            notifyWiredAccessoryChanged(0, switchValues,
                    SW_HEADPHONE_INSERT_BIT | SW_MICROPHONE_INSERT_BIT);
        }

        mObserver.init();
    }
在WiredAccessoryManager中实例化了一个WiredAccessoryObserver,其就是通过UEvent方式来检测耳机的插入拔出状态,

        public WiredAccessoryObserver() {
            mUEventInfo = makeObservedUEventList();
        }
        private List<UEventInfo> makeObservedUEventList() {
            List<UEventInfo> retVal = new ArrayList<UEventInfo>();
            UEventInfo uei;

            // Monitor h2w
            if (!mUseDevInputEventForAudioJack) {
                uei = new UEventInfo(NAME_H2W, BIT_HEADSET, BIT_HEADSET_NO_MIC);
                if (uei.checkSwitchExists()) {
                    retVal.add(uei);
                } else {
                    Slog.w(TAG, "This kernel does not have wired headset support");
                }
            }

            // Monitor USB
            uei = new UEventInfo(NAME_USB_AUDIO, BIT_USB_HEADSET_ANLG, BIT_USB_HEADSET_DGTL);
            if (uei.checkSwitchExists()) {
                retVal.add(uei);
            } else {
                Slog.w(TAG, "This kernel does not have usb audio support");
            }

            // Monitor HDMI
            uei = new UEventInfo(NAME_HDMI_AUDIO, BIT_HDMI_AUDIO, 0);
            if (uei.checkSwitchExists()) {
                retVal.add(uei);
            } else {
                uei = new UEventInfo(NAME_HDMI, BIT_HDMI_AUDIO, 0);
                if (uei.checkSwitchExists()) {
                    retVal.add(uei);
                } else {
                    Slog.w(TAG, "This kernel does not have HDMI audio support");
                }
            }

            return retVal;
        }
在WiredAccessoryObserver 的init中

        void init() {
            synchronized (mLock) {
                if (LOG) Slog.v(TAG, "init()");
                char[] buffer = new char[1024];

                for (int i = 0; i < mUEventInfo.size(); ++i) {
                    UEventInfo uei = mUEventInfo.get(i);
                    try {
                        int curState;
                        FileReader file = new FileReader(uei.getSwitchStatePath());
                        int len = file.read(buffer, 0, 1024);
                        file.close();
                        curState = Integer.valueOf((new String(buffer, 0, len)).trim());

                        if (curState > 0) {
                            updateStateLocked(uei.getDevPath(), uei.getDevName(), curState);
                        }
                    } catch (FileNotFoundException e) {
                        Slog.w(TAG, uei.getSwitchStatePath() +
                                " not found while attempting to determine initial switch state");
                    } catch (Exception e) {
                        Slog.e(TAG, "" , e);
                    }
                }
            }

            // At any given time accessories could be inserted
            // one on the board, one on the dock and one on HDMI:
            // observe three UEVENTs
            // 设置监听节点,开始进行监听
            for (int i = 0; i < mUEventInfo.size(); ++i) {
                UEventInfo uei = mUEventInfo.get(i);
                startObserving("DEVPATH="+uei.getDevPath());
            }
        }
        public String getDevPath() {
            return String.format(Locale.US, "/devices/virtual/switch/%s", mDevName);
        } 
通过startObserving("DEVPATH="+uei.getDevPath()); 来进行监听,监听的节点是:

shell@hammerhead:/ $ ls sys/class/switch/ -l                                  

lrwxrwxrwx root     root              2014-05-06 09:44 h2w -> ../../devices/virtual/switch/h2w

    /**
     * Begin observation of UEvent's.<p>
     * This method will cause the UEvent thread to start if this is the first
     * invocation of startObserving in this process.<p>
     * Once called, the UEvent thread will call onUEvent() when an incoming
     * UEvent matches the specified string.<p>
     * This method can be called multiple times to register multiple matches.
     * Only one call to stopObserving is required even with multiple registered
     * matches.
     *
     * @param match A substring of the UEvent to match.  Try to be as specific
     * as possible to avoid incurring unintended additional cost from processing
     * irrelevant messages.  Netlink messages can be moderately high bandwidth and
     * are expensive to parse.  For example, some devices may send one netlink message
     * for each vsync period.
     */
    public final void startObserving(String match) {
        if (match == null || match.isEmpty()) {
            throw new IllegalArgumentException("match substring must be non-empty");
        }

        final UEventThread t = getThread();
        t.addObserver(match, this);
    }
在onUEvent时间到来的时候更新state
        @Override
        public void onUEvent(UEventObserver.UEvent event) {
            if (LOG) Slog.v(TAG, "Headset UEVENT: " + event.toString());

            try {
                String devPath = event.get("DEVPATH");
                String name = event.get("SWITCH_NAME");
                int state = Integer.parseInt(event.get("SWITCH_STATE"));
                synchronized (mLock) {
                    updateStateLocked(devPath, name, state);
                }
            } catch (NumberFormatException e) {
                Slog.e(TAG, "Could not parse switch state from event " + event);
            }
        }
updateStateLocked(devPath, name, state)
->   updateLocked(String newName, int newState)  
->   setDevicesState(int headsetState, int prevHeadsetState, String headsetName)  
->   setDeviceStateLocked()
->  mAudioManager.setWiredDeviceConnectionState(device, state, headsetName);在setDeviceStateLocked中会更新device的状态,并最终调用mAudioManager.setWiredDeviceConnectionState
    private void setDevicesState(
            int headsetState, int prevHeadsetState, String headsetName) {
        synchronized (mLock) {
            int allHeadsets = SUPPORTED_HEADSETS;
            for (int curHeadset = 1; allHeadsets != 0; curHeadset <<= 1) {
                if ((curHeadset & allHeadsets) != 0) {
                    setDeviceStateLocked(curHeadset, headsetState, prevHeadsetState, headsetName);
                    allHeadsets &= ~curHeadset;
                }
            }
        }
    }

    private void setDeviceStateLocked(int headset,
            int headsetState, int prevHeadsetState, String headsetName) {
        if ((headsetState & headset) != (prevHeadsetState & headset)) {
            int device;
            int state;

            if ((headsetState & headset) != 0) {
                state = 1;
            } else {
                state = 0;
            }

            if (hea
  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值