android系统在播放音乐的时候拔掉耳机通常音乐会自动暂停播放。遇到这样的需求,客户使用的是一个usb audio设备,希望拔掉后音乐不会自动暂停,而是继续播放,声音从speaker出来。以5.1的code为例,usb audio设备(usb 耳机等)拔出时\frameworks\base\services\usb\java\com\android\server\usbAudioService.java中会发出一个断开的广播:

private void sendDeviceNotification(AudioDevice audioDevice, boolean enabled) {        // send a sticky broadcast containing current USB state        Intent intent = new Intent(AudioManager.ACTION_USB_AUDIO_DEVICE_PLUG);        intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);        intent.putExtra("state", enabled ? 1 : 0);        intent.putExtra("card", audioDevice.mCard);        intent.putExtra("device", audioDevice.mDevice);        intent.putExtra("hasPlayback", audioDevice.mHasPlayback);        intent.putExtra("hasCapture", audioDevice.mHasCapture);        intent.putExtra("hasMIDI", audioDevice.mHasMIDI);        mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);    }


AudioService接受并处理这个广播,具体代码在frameworks\base\media\java\android\media\AudioService.java中onReceive方法中:

 } else if (action.equals(AudioManager.ACTION_USB_AUDIO_DEVICE_PLUG)) {                // FIXME Does not yet handle the case where the setting is changed                // after device connection.  Ideally we should handle the settings change                // in SettingsObserver. Here we should log that a USB device is connected                // and disconnected with its address (card , device) and force the                // connection or disconnection when the setting changes.                int isDisabled = Settings.Secure.getInt(mContentResolver,                        Settings.Secure.USB_AUDIO_AUTOMATIC_ROUTING_DISABLED, 0);                if (isDisabled != 0) {                    return;                }                state = intent.getIntExtra("state", 0);                int alsaCard = intent.getIntExtra("card", -1);                int alsaDevice = intent.getIntExtra("device", -1);                boolean hasPlayback = intent.getBooleanExtra("hasPlayback", false);                boolean hasCapture = intent.getBooleanExtra("hasCapture", false);                boolean hasMIDI = intent.getBooleanExtra("hasMIDI", false);                String ID = intent.getStringExtra("ID");                String usbHeadSetID = "1a1d00e0";                String params = (alsaCard == -1 && alsaDevice == -1 ? ""                                    : "card=" + alsaCard + ";device=" + alsaDevice);                // Playback Device                if (hasPlayback) {                    outDevice = AudioSystem.DEVICE_OUT_USB_DEVICE;                    setWiredDeviceConnectionState(outDevice, state, params);                }                // Capture Device                if (hasCapture) {                    inDevice = AudioSystem.DEVICE_IN_USB_DEVICE;                    setWiredDeviceConnectionState(inDevice, state, params);                }


再来看setWiredDeviceConnectionState方法:

    public void setWiredDeviceConnectionState(int device, int state, String name) {        synchronized (mConnectedDevices) {            int delay = checkSendBecomingNoisyIntent(device, state);            queueMsgUnderWakeLock(mAudioHandler,                    MSG_SET_WIRED_DEVICE_CONNECTION_STATE,                    device,                    state,                    name,                    delay);        }    }

其中checkSendBecomingNoisyIntent又发个一个消息通知给到上层:

    private int checkSendBecomingNoisyIntent(int device, int state) {        int delay = 0;        if ((state == 0) && ((device & mBecomingNoisyIntentDevices) != 0)) {            int devices = 0;            for (int dev : mConnectedDevices.keySet()) {                if (((dev & AudioSystem.DEVICE_BIT_IN) == 0) &&                        ((dev & mBecomingNoisyIntentDevices) != 0)) {                   devices |= dev;                }            }            if (devices == device) {                sendMsg(mAudioHandler,                        MSG_BROADCAST_AUDIO_BECOMING_NOISY,                        SENDMSG_REPLACE,                        0,                        0,                        null,                        0);                delay = 1000;            }        }

MSG_BROADCAST_AUDIO_BECOMING_NOISY
这个消息对应audiomanager中的这个类型:ACTION_AUDIO_BECOMING_NOISY

应用收到这个通知后会做一个暂停的处理,

在底层可以直接不发这个通知,只针对usb audio设备可以这样修改,判断是否是usb audio设备 ,是就不发好了:

 private int checkSendBecomingNoisyIntent(int device, int state) {        int delay = 0;        if ((state == 0) && ((device & mBecomingNoisyIntentDevices) != 0)) {            int devices = 0;            for (int dev : mConnectedDevices.keySet()) {                if (((dev & AudioSystem.DEVICE_BIT_IN) == 0) &&                        ((dev & mBecomingNoisyIntentDevices) != 0)) {                   devices |= dev;                }            }            if (devices == device && device != AudioSystem.DEVICE_OUT_USB_DEVICE && device !=AudioSystem.DEVICE_IN_USB_DEVICE) {                sendMsg(mAudioHandler,                        MSG_BROADCAST_AUDIO_BECOMING_NOISY,                        SENDMSG_REPLACE,                        0,                        0,                        null,                        0);                delay = 1000;            }        }

这样,usb audio设备拔出来音乐就不会暂停而是从扬声器输出继续播放了。


更多相关文章

  1. Android——adb工具的使用
  2. 这款开源 Android(安卓)实时投屏软件是 Qt 做的
  3. Android(安卓)通知栏Notification的整合 全面学习 (一个DEMO让你
  4. android播放音乐的三种方法实现
  5. ADB常用操作
  6. X-Ray检测Android设备Root漏洞过程分析
  7. unity obb 分包 上传googleplay
  8. [Android(安卓)Training视频系列]1.2 Running Your App
  9. Android(安卓)adb 命令大全

随机推荐

  1. 隐式启动Activity 报ActivityNotFoundExc
  2. Android(安卓)问题记录
  3. 获取Android(安卓)手机屏幕宽度和高度以
  4. android多选联系人实现
  5. Android(安卓)Studio Start Failed解决方
  6. Android源码下载
  7. 从中间扩展和缩小
  8. 有关Material Design新特性的详解。
  9. android maven Unable to execute dex: M
  10. Power Profiles for Android