Audio笔记之耳机插拔检测
来源:互联网 发布:什么软件可以升级显卡 编辑:程序博客网 时间:2024/06/10 03:18
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 (headset == BIT_HEADSET) { device = AudioManager.DEVICE_OUT_WIRED_HEADSET; } else if (headset == BIT_HEADSET_NO_MIC){ device = AudioManager.DEVICE_OUT_WIRED_HEADPHONE; } else if (headset == BIT_USB_HEADSET_ANLG) { device = AudioManager.DEVICE_OUT_ANLG_DOCK_HEADSET; } else if (headset == BIT_USB_HEADSET_DGTL) { device = AudioManager.DEVICE_OUT_DGTL_DOCK_HEADSET; } else if (headset == BIT_HDMI_AUDIO) { device = AudioManager.DEVICE_OUT_AUX_DIGITAL; } else { Slog.e(TAG, "setDeviceState() invalid headset type: "+headset); return; } if (LOG) Slog.v(TAG, "device "+headsetName+((state == 1) ? " connected" : " disconnected")); mAudioManager.setWiredDeviceConnectionState(device, state, headsetName); } } public void setWiredDeviceConnectionState(int device, int state, String name) { IAudioService service = getService(); try { service.setWiredDeviceConnectionState(device, state, name); } catch (RemoteException e) { Log.e(TAG, "Dead object in setWiredDeviceConnectionState "+e); } } //AudioService进行处理设备插拔的消息 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); } } private void queueMsgUnderWakeLock(Handler handler, int msg, int arg1, int arg2, Object obj, int delay) { final long ident = Binder.clearCallingIdentity(); // Always acquire the wake lock as AudioService because it is released by the // message handler. mAudioEventWakeLock.acquire(); Binder.restoreCallingIdentity(ident); sendMsg(handler, msg, SENDMSG_QUEUE, arg1, arg2, obj, delay); } private static void sendMsg(Handler handler, int msg, int existingMsgPolicy, int arg1, int arg2, Object obj, int delay) { if (existingMsgPolicy == SENDMSG_REPLACE) { handler.removeMessages(msg); } else if (existingMsgPolicy == SENDMSG_NOOP && handler.hasMessages(msg)) { return; } handler.sendMessageDelayed(handler.obtainMessage(msg, arg1, arg2, obj), delay); } //AudioHandler处理消息MSG_SET_WIRED_DEVICE_CONNECTION_STATE private void onSetWiredDeviceConnectionState(int device, int state, String name) { synchronized (mConnectedDevices) { //步骤一、如果是耳机设备的拔除,强制设置A2DP if ((state == 0) && ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) || (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE))) { setBluetoothA2dpOnInt(true); } //步骤二、所有设备的处理 boolean isUsb = ((device & AudioSystem.DEVICE_OUT_ALL_USB) != 0); handleDeviceConnection((state == 1), device, (isUsb ? name : "")); //步骤三、如果是耳机设备插入,强制设置A2DP无效 if (state != 0) { if ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) || (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE)) { setBluetoothA2dpOnInt(false); } if ((device & mSafeMediaVolumeDevices) != 0) { sendMsg(mAudioHandler, MSG_CHECK_MUSIC_ACTIVE, SENDMSG_REPLACE, 0, 0, null, MUSIC_ACTIVE_POLL_PERIOD_MS); } } //步骤四、非USB设备的处理 if (!isUsb) { sendDeviceConnectionIntent(device, state, name); } } } //步骤一、 对A2DP设备的处理,如果是插入操作,强制关闭A2DP // Handles request to override default use of A2DP for media. public void setBluetoothA2dpOnInt(boolean on) { synchronized (mBluetoothA2dpEnabledLock) { mBluetoothA2dpEnabled = on; mAudioHandler.removeMessages(MSG_SET_FORCE_BT_A2DP_USE); AudioSystem.setForceUse(AudioSystem.FOR_MEDIA, mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP); } } // 步骤二、处理所有设备连接的事件 private boolean handleDeviceConnection(boolean connected, int device, String params) { synchronized (mConnectedDevices) { boolean isConnected = (mConnectedDevices.containsKey(device) && (params.isEmpty() || mConnectedDevices.get(device).equals(params))); //移除动作 if (isConnected && !connected) { AudioSystem.setDeviceConnectionState(device, AudioSystem.DEVICE_STATE_UNAVAILABLE, mConnectedDevices.get(device)); mConnectedDevices.remove(device); return true; } else if (!isConnected && connected) {//插入动作 AudioSystem.setDeviceConnectionState(device, AudioSystem.DEVICE_STATE_AVAILABLE, params); mConnectedDevices.put(new Integer(device), params); return true; } } return false; } //步骤四、如果不是USB设备,发送消息和广播 private void sendDeviceConnectionIntent(int device, int state, String name) { Intent intent = new Intent(); intent.putExtra("state", state); intent.putExtra("name", name); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); int connType = 0; if (device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) { connType = AudioRoutesInfo.MAIN_HEADSET; intent.setAction(Intent.ACTION_HEADSET_PLUG); intent.putExtra("microphone", 1); } else if (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) { connType = AudioRoutesInfo.MAIN_HEADPHONES; intent.setAction(Intent.ACTION_HEADSET_PLUG); intent.putExtra("microphone", 0); } else if (device == AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET) { connType = AudioRoutesInfo.MAIN_DOCK_SPEAKERS; intent.setAction(Intent.ACTION_ANALOG_AUDIO_DOCK_PLUG); } else if (device == AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET) { connType = AudioRoutesInfo.MAIN_DOCK_SPEAKERS; intent.setAction(Intent.ACTION_DIGITAL_AUDIO_DOCK_PLUG); } else if (device == AudioSystem.DEVICE_OUT_AUX_DIGITAL) { connType = AudioRoutesInfo.MAIN_HDMI; intent.setAction(Intent.ACTION_HDMI_AUDIO_PLUG); } //根据不同的设备连接类型切换声道 synchronized (mCurAudioRoutes) { if (connType != 0) { int newConn = mCurAudioRoutes.mMainType; if (state != 0) { newConn |= connType; } else { newConn &= ~connType; } //通过IAudioRoutesObserver接口调用dispatchAudioRoutesChanged //函数来通知媒体路由切换相关进程和服务进行相应处理。 if (newConn != mCurAudioRoutes.mMainType) { mCurAudioRoutes.mMainType = newConn; sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES, SENDMSG_NOOP, 0, 0, null, 0); } } } //给上层发广播,进行事件通知,不过在AudioServiceBroadcastReceiver中没有找到这些action的处理 final long ident = Binder.clearCallingIdentity(); try { ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL); } finally { Binder.restoreCallingIdentity(ident); } } //AudioHandler处理消息MSG_REPORT_NEW_ROUTES public void handleMessage(Message msg) { case MSG_REPORT_NEW_ROUTES: { int N = mRoutesObservers.beginBroadcast(); if (N > 0) { AudioRoutesInfo routes; synchronized (mCurAudioRoutes) { routes = new AudioRoutesInfo(mCurAudioRoutes); } while (N > 0) { N--; IAudioRoutesObserver obs = mRoutesObservers.getBroadcastItem(N); try { //调用注册的IAudioRoutesObserver对象 obs.dispatchAudioRoutesChanged(routes); } catch (RemoteException e) { } } } mRoutesObservers.finishBroadcast(); break; } } //其它对象或应用可以调用service的该对象来进行注册,后续如果route有变化,service会通知这些对象 @Override public AudioRoutesInfo startWatchingRoutes(IAudioRoutesObserver observer) { synchronized (mCurAudioRoutes) { AudioRoutesInfo routes = new AudioRoutesInfo(mCurAudioRoutes); mRoutesObservers.register(observer); return routes; } }接着调用AudioSystem.java,通过JNI.层,进入到AudioSystem.c
//继续分析步骤二,接着进行handleDeviceConnection函数调用status_t AudioSystem::setDeviceConnectionState(audio_devices_t device, audio_policy_dev_state_t state, const char *device_address){ const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service(); const char *address = ""; if (aps == 0) return PERMISSION_DENIED; if (device_address != NULL) { address = device_address; } return aps->setDeviceConnectionState(device, state, address);}最终会调用到AuidoPolicyMnangerBase.cpp
status_t AudioPolicyManagerBase::setDeviceConnectionState(audio_devices_t device, AudioSystem::device_connection_state state, const char *device_address){ SortedVector <audio_io_handle_t> outputs; ALOGV("setDeviceConnectionState() device: %x, state %d, address %s", device, state, device_address); // connect/disconnect only 1 device at a time if (!audio_is_output_device(device) && !audio_is_input_device(device)) return BAD_VALUE; if (strlen(device_address) >= MAX_DEVICE_ADDRESS_LEN) { ALOGE("setDeviceConnectionState() invalid address: %s", device_address); return BAD_VALUE; } // 处理输出设备的插拔 // handle output devices if (audio_is_output_device(device)) { if (!mHasA2dp && audio_is_a2dp_device(device)) { ALOGE("setDeviceConnectionState() invalid A2DP device: %x", device); return BAD_VALUE; } if (!mHasUsb && audio_is_usb_device(device)) { ALOGE("setDeviceConnectionState() invalid USB audio device: %x", device); return BAD_VALUE; } if (!mHasRemoteSubmix && audio_is_remote_submix_device((audio_devices_t)device)) { ALOGE("setDeviceConnectionState() invalid remote submix audio device: %x", device); return BAD_VALUE; } // save a copy of the opened output descriptors before any output is opened or closed // by checkOutputsForDevice(). This will be needed by checkOutputForAllStrategies() mPreviousOutputs = mOutputs; // 设置可用设备对应位, switch (state) { // handle output device connection case AudioSystem::DEVICE_STATE_AVAILABLE: if (mAvailableOutputDevices & device) { ALOGW("setDeviceConnectionState() device already connected: %x", device); return INVALID_OPERATION; } ALOGV("setDeviceConnectionState() connecting device %x", device); if (checkOutputsForDevice(device, state, outputs) != NO_ERROR) { return INVALID_OPERATION; } ALOGV("setDeviceConnectionState() checkOutputsForDevice() returned %d outputs", outputs.size()); // register new device as available // 将插入的设备在可用设备变量中对应的位置1 mAvailableOutputDevices = (audio_devices_t)(mAvailableOutputDevices | device); if (!outputs.isEmpty()) { String8 paramStr; if (mHasA2dp && audio_is_a2dp_device(device)) { // handle A2DP device connection AudioParameter param; param.add(String8(AUDIO_PARAMETER_A2DP_SINK_ADDRESS), String8(device_address)); paramStr = param.toString(); mA2dpDeviceAddress = String8(device_address, MAX_DEVICE_ADDRESS_LEN); mA2dpSuspended = false; } else if (audio_is_bluetooth_sco_device(device)) { // handle SCO device connection mScoDeviceAddress = String8(device_address, MAX_DEVICE_ADDRESS_LEN); } else if (mHasUsb && audio_is_usb_device(device)) { // handle USB device connection mUsbCardAndDevice = String8(device_address, MAX_DEVICE_ADDRESS_LEN); paramStr = mUsbCardAndDevice; } // not currently handling multiple simultaneous submixes: ignoring remote submix // case and address if (!paramStr.isEmpty()) { for (size_t i = 0; i < outputs.size(); i++) { mpClientInterface->setParameters(outputs[i], paramStr); } } } break; // handle output device disconnection case AudioSystem::DEVICE_STATE_UNAVAILABLE: { if (!(mAvailableOutputDevices & device)) { ALOGW("setDeviceConnectionState() device not connected: %x", device); return INVALID_OPERATION; } ALOGV("setDeviceConnectionState() disconnecting device %x", device); // remove device from available output devices // 将拔除的设备在可用设备变量中对应的位置0 mAvailableOutputDevices = (audio_devices_t)(mAvailableOutputDevices & ~device); checkOutputsForDevice(device, state, outputs); if (mHasA2dp && audio_is_a2dp_device(device)) { // handle A2DP device disconnection mA2dpDeviceAddress = ""; mA2dpSuspended = false; } else if (audio_is_bluetooth_sco_device(device)) { // handle SCO device disconnection mScoDeviceAddress = ""; } else if (mHasUsb && audio_is_usb_device(device)) { // handle USB device disconnection mUsbCardAndDevice = ""; } // not currently handling multiple simultaneous submixes: ignoring remote submix // case and address } break; default: ALOGE("setDeviceConnectionState() invalid state: %x", state); return BAD_VALUE; } //步骤一、更新A2DP设备的状态 checkA2dpSuspend(); //步骤二、更新所有的Strategy对应的output checkOutputForAllStrategies(); // outputs must be closed after checkOutputForAllStrategies() is executed if (!outputs.isEmpty()) { for (size_t i = 0; i < outputs.size(); i++) { // close unused outputs after device disconnection or direct outputs that have been // opened by checkOutputsForDevice() to query dynamic parameters if ((state == AudioSystem::DEVICE_STATE_UNAVAILABLE) || (mOutputs.valueFor(outputs[i])->mFlags & AUDIO_OUTPUT_FLAG_DIRECT)) { closeOutput(outputs[i]); } } } //步骤三、更新当前系统可用的输出设备 updateDevicesAndOutputs(); //步骤四、 for (size_t i = 0; i < mOutputs.size(); i++) { // do not force device change on duplicated output because if device is 0, it will // also force a device 0 for the two outputs it is duplicated to which may override // a valid device selection on those outputs. setOutputDevice(mOutputs.keyAt(i), getNewDevice(mOutputs.keyAt(i), true /*fromCache*/), !mOutputs.valueAt(i)->isDuplicated(), 0); } if (device == AUDIO_DEVICE_OUT_WIRED_HEADSET) { device = AUDIO_DEVICE_IN_WIRED_HEADSET; } else if (device == AUDIO_DEVICE_OUT_BLUETOOTH_SCO || device == AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET || device == AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT) { device = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET; } else { return NO_ERROR; } } // 处理输入设备的插拔 // handle input devices if (audio_is_input_device(device)) { switch (state) { // handle input device connection case AudioSystem::DEVICE_STATE_AVAILABLE: { if (mAvailableInputDevices & device) { ALOGW("setDeviceConnectionState() device already connected: %d", device); return INVALID_OPERATION; } mAvailableInputDevices = mAvailableInputDevices | (device & ~AUDIO_DEVICE_BIT_IN); } break; // handle input device disconnection case AudioSystem::DEVICE_STATE_UNAVAILABLE: { if (!(mAvailableInputDevices & device)) { ALOGW("setDeviceConnectionState() device not connected: %d", device); return INVALID_OPERATION; } mAvailableInputDevices = (audio_devices_t) (mAvailableInputDevices & ~device); } break; default: ALOGE("setDeviceConnectionState() invalid state: %x", state); return BAD_VALUE; } audio_io_handle_t activeInput = getActiveInput(); if (activeInput != 0) { AudioInputDescriptor *inputDesc = mInputs.valueFor(activeInput); audio_devices_t newDevice = getDeviceForInputSource(inputDesc->mInputSource); if ((newDevice != AUDIO_DEVICE_NONE) && (newDevice != inputDesc->mDevice)) { ALOGV("setDeviceConnectionState() changing device from %x to %x for input %d", inputDesc->mDevice, newDevice, activeInput); inputDesc->mDevice = newDevice; AudioParameter param = AudioParameter(); param.addInt(String8(AudioParameter::keyRouting), (int)newDevice); mpClientInterface->setParameters(activeInput, param.toString()); } } return NO_ERROR; } ALOGW("setDeviceConnectionState() invalid device: %x", device); return BAD_VALUE;}
//步骤一、设置A2DP设备的状态
void AudioPolicyManagerBase::checkA2dpSuspend(){ if (!mHasA2dp) { return; } //找到A2DP的输出线程 audio_io_handle_t a2dpOutput = getA2dpOutput(); if (a2dpOutput == 0) { return; } // suspend A2DP output if: // (NOT already suspended) && // ((SCO device is connected && // (forced usage for communication || for record is SCO))) || // (phone state is ringing || in call) // // restore A2DP output if: // (Already suspended) && // ((SCO device is NOT connected || // (forced usage NOT for communication && NOT for record is SCO))) && // (phone state is NOT ringing && NOT in call) // 如果处于暂停状态,则进行重置,否则进入暂停状态 if (mA2dpSuspended) { if (((mScoDeviceAddress == "") || ((mForceUse[AudioSystem::FOR_COMMUNICATION] != AudioSystem::FORCE_BT_SCO) && (mForceUse[AudioSystem::FOR_RECORD] != AudioSystem::FORCE_BT_SCO))) && ((mPhoneState != AudioSystem::MODE_IN_CALL) && (mPhoneState != AudioSystem::MODE_RINGTONE))) { mpClientInterface->restoreOutput(a2dpOutput); mA2dpSuspended = false; } } else { if (((mScoDeviceAddress != "") && ((mForceUse[AudioSystem::FOR_COMMUNICATION] == AudioSystem::FORCE_BT_SCO) || (mForceUse[AudioSystem::FOR_RECORD] == AudioSystem::FORCE_BT_SCO))) || ((mPhoneState == AudioSystem::MODE_IN_CALL) || (mPhoneState == AudioSystem::MODE_RINGTONE))) { mpClientInterface->suspendOutput(a2dpOutput); mA2dpSuspended = true; } }}//查找A2DP类型的输出线程,对应conf文件中的一个profile对象,audio_io_handle_t AudioPolicyManagerBase::getA2dpOutput(){ if (!mHasA2dp) { return 0; } for (size_t i = 0; i < mOutputs.size(); i++) { AudioOutputDescriptor *outputDesc = mOutputs.valueAt(i); if (!outputDesc->isDuplicated() && outputDesc->device() & AUDIO_DEVICE_OUT_ALL_A2DP) { return mOutputs.keyAt(i); } } return 0;}status_t AudioPolicyCompatClient::suspendOutput(audio_io_handle_t output){ return mServiceOps->suspend_output(mService, output);}//mServiceOps实际上是audio_policy_service_opsstatic int aps_suspend_output(void *service, audio_io_handle_t output){ sp<IAudioFlinger> af = AudioSystem::get_audio_flinger(); if (af == 0) { ALOGW("%s: could not get AudioFlinger", __func__); return PERMISSION_DENIED; } return af->suspendOutput(output);}//暂停该输出线程status_t AudioFlinger::suspendOutput(audio_io_handle_t output){ Mutex::Autolock _l(mLock); PlaybackThread *thread = checkPlaybackThread_l(output); if (thread == NULL) { return BAD_VALUE; } ALOGV("suspendOutput() %d", output); thread->suspend(); return NO_ERROR;}
//步骤二、更新所有的Strategy对应的output
void AudioPolicyManagerBase::checkOutputForAllStrategies(){ checkOutputForStrategy(STRATEGY_ENFORCED_AUDIBLE); checkOutputForStrategy(STRATEGY_PHONE); checkOutputForStrategy(STRATEGY_SONIFICATION); checkOutputForStrategy(STRATEGY_SONIFICATION_RESPECTFUL); checkOutputForStrategy(STRATEGY_MEDIA); checkOutputForStrategy(STRATEGY_DTMF);}void AudioPolicyManagerBase::checkOutputForStrategy(routing_strategy strategy){ audio_devices_t oldDevice = getDeviceForStrategy(strategy, true /*fromCache*/); audio_devices_t newDevice = getDeviceForStrategy(strategy, false /*fromCache*/); SortedVector<audio_io_handle_t> srcOutputs = getOutputsForDevice(oldDevice, mPreviousOutputs); SortedVector<audio_io_handle_t> dstOutputs = getOutputsForDevice(newDevice, mOutputs); //如果设备的插拔导致了Strategy关联的输出发生了变化,则需要调整Strategy相关的Effect和Track //到新的输出上 if (!vectorsEqual(srcOutputs,dstOutputs)) { ALOGV("checkOutputForStrategy() strategy %d, moving from output %d to output %d", strategy, srcOutputs[0], dstOutputs[0]); // mute strategy while moving tracks from one output to another for (size_t i = 0; i < srcOutputs.size(); i++) { AudioOutputDescriptor *desc = mOutputs.valueFor(srcOutputs[i]); //通过检查Stream的引用数,判断对应的Strategy是否处于活动状态 //每个Output都会保存关联的所有Stream的数量,如果Stream都为0, //则表示该Output没有在输出任何声音 if (desc->isStrategyActive(strategy)) { setStrategyMute(strategy, true, srcOutputs[i]); setStrategyMute(strategy, false, srcOutputs[i], MUTE_TIME_MS, newDevice); } } // Move effects associated to this strategy from previous output to new output if (strategy == STRATEGY_MEDIA) { int outIdx = 0; for (size_t i = 0; i < dstOutputs.size(); i++) { AudioOutputDescriptor *desc = mOutputs.valueFor(dstOutputs[i]); if (desc->mFlags & AUDIO_OUTPUT_FLAG_DEEP_BUFFER) { outIdx = i; } } SortedVector<audio_io_handle_t> moved; for (size_t i = 0; i < mEffects.size(); i++) { EffectDescriptor *desc = mEffects.valueAt(i); if (desc->mSession == AUDIO_SESSION_OUTPUT_MIX && desc->mIo != dstOutputs[outIdx]) { if (moved.indexOf(desc->mIo) < 0) { ALOGV("checkOutputForStrategy() moving effect %d to output %d", mEffects.keyAt(i), dstOutputs[outIdx]); mpClientInterface->moveEffects(AUDIO_SESSION_OUTPUT_MIX, desc->mIo, dstOutputs[outIdx]); moved.add(desc->mIo); } desc->mIo = dstOutputs[outIdx]; } } } // Move tracks associated to this strategy from previous output to new output for (int i = 0; i < (int)AudioSystem::NUM_STREAM_TYPES; i++) { if (getStrategy((AudioSystem::stream_type)i) == strategy) { //FIXME see fixme on name change mpClientInterface->setStreamOutput((AudioSystem::stream_type)i, dstOutputs[0] /* ignored */); } } }}//反向推导,查找与该Strategy关联的Stream,然后将该void AudioPolicyManagerBase::setStrategyMute(routing_strategy strategy, bool on, audio_io_handle_t output, int delayMs, audio_devices_t device){ ALOGVV("setStrategyMute() strategy %d, mute %d, output %d", strategy, on, output); for (int stream = 0; stream < AudioSystem::NUM_STREAM_TYPES; stream++) { if (getStrategy((AudioSystem::stream_type)stream) == strategy) { setStreamMute(stream, on, output, delayMs, device); } }}void AudioPolicyManagerBase::setStreamMute(int stream, bool on, audio_io_handle_t output, int delayMs, audio_devices_t device){ StreamDescriptor &streamDesc = mStreams[stream]; AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output); if (device == AUDIO_DEVICE_NONE) { device = outputDesc->device(); } ALOGVV("setStreamMute() stream %d, mute %d, output %d, mMuteCount %d device %04x", stream, on, output, outputDesc->mMuteCount[stream], device); if (on) { if (outputDesc->mMuteCount[stream] == 0) { if (streamDesc.mCanBeMuted && ((stream != AudioSystem::ENFORCED_AUDIBLE) || (mForceUse[AudioSystem::FOR_SYSTEM] == AudioSystem::FORCE_NONE))) { checkAndSetVolume(stream, 0, output, device, delayMs); } } // increment mMuteCount after calling checkAndSetVolume() so that volume change is not ignored outputDesc->mMuteCount[stream]++; } else { if (outputDesc->mMuteCount[stream] == 0) { ALOGV("setStreamMute() unmuting non muted stream!"); return; } if (--outputDesc->mMuteCount[stream] == 0) { checkAndSetVolume(stream, streamDesc.getVolumeIndex(device), output, device, delayMs); } }}status_t AudioPolicyManagerBase::checkAndSetVolume(int stream, int index, audio_io_handle_t output, audio_devices_t device, int delayMs, bool force){ // do not change actual stream volume if the stream is muted if (mOutputs.valueFor(output)->mMuteCount[stream] != 0) { ALOGVV("checkAndSetVolume() stream %d muted count %d", stream, mOutputs.valueFor(output)->mMuteCount[stream]); return NO_ERROR; } // do not change in call volume if bluetooth is connected and vice versa if ((stream == AudioSystem::VOICE_CALL && mForceUse[AudioSystem::FOR_COMMUNICATION] == AudioSystem::FORCE_BT_SCO) || (stream == AudioSystem::BLUETOOTH_SCO && mForceUse[AudioSystem::FOR_COMMUNICATION] != AudioSystem::FORCE_BT_SCO)) { ALOGV("checkAndSetVolume() cannot set stream %d volume with force use = %d for comm", stream, mForceUse[AudioSystem::FOR_COMMUNICATION]); return INVALID_OPERATION; } float volume = computeVolume(stream, index, output, device); // We actually change the volume if: // - the float value returned by computeVolume() changed // - the force flag is set if (volume != mOutputs.valueFor(output)->mCurVolume[stream] || force) { mOutputs.valueFor(output)->mCurVolume[stream] = volume; ALOGVV("checkAndSetVolume() for output %d stream %d, volume %f, delay %d", output, stream, volume, delayMs); // Force VOICE_CALL to track BLUETOOTH_SCO stream volume when bluetooth audio is // enabled if (stream == AudioSystem::BLUETOOTH_SCO) { mpClientInterface->setStreamVolume(AudioSystem::VOICE_CALL, volume, output, delayMs); } mpClientInterface->setStreamVolume((AudioSystem::stream_type)stream, volume, output, delayMs); } if (stream == AudioSystem::VOICE_CALL || stream == AudioSystem::BLUETOOTH_SCO) { float voiceVolume; // Force voice volume to max for bluetooth SCO as volume is managed by the headset if (stream == AudioSystem::VOICE_CALL) { voiceVolume = (float)index/(float)mStreams[stream].mIndexMax; } else { voiceVolume = 1.0; } if (voiceVolume != mLastVoiceVolume && output == mPrimaryOutput) { mpClientInterface->setVoiceVolume(voiceVolume, delayMs); mLastVoiceVolume = voiceVolume; } } return NO_ERROR;}status_t AudioFlinger::setStreamVolume(audio_stream_type_t stream, float value, audio_io_handle_t output){ // check calling permissions if (!settingsAllowed()) { return PERMISSION_DENIED; } if (uint32_t(stream) >= AUDIO_STREAM_CNT) { ALOGE("setStreamVolume() invalid stream %d", stream); return BAD_VALUE; } AutoMutex lock(mLock); PlaybackThread *thread = NULL; if (output) { thread = checkPlaybackThread_l(output); if (thread == NULL) { return BAD_VALUE; } } mStreamTypes[stream].volume = value; if (thread == NULL) { for (size_t i = 0; i < mPlaybackThreads.size(); i++) { mPlaybackThreads.valueAt(i)->setStreamVolume(stream, value); } } else { thread->setStreamVolume(stream, value); } return NO_ERROR;}void AudioFlinger::PlaybackThread::setStreamVolume(audio_stream_type_t stream, float value){ Mutex::Autolock _l(mLock); mStreamTypes[stream].volume = value;}//步骤三、更新当前系统可用的输出设备setOutputDevice(mOutputs.keyAt(i), getNewDevice(mOutputs.keyAt(i), true /*fromCache*/), !mOutputs.valueAt(i)->isDuplicated(), 0);// 设备插拔事件导致当前系统设备有变化,首先需要根据Strategy获得设备,然后重新分配给outputaudio_devices_t AudioPolicyManagerBase::getNewDevice(audio_io_handle_t output, bool fromCache){ audio_devices_t device = AUDIO_DEVICE_NONE; AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output); // check the following by order of priority to request a routing change if necessary: // 1: the strategy enforced audible is active on the output: // use device for strategy enforced audible // 2: we are in call or the strategy phone is active on the output: // use device for strategy phone // 3: the strategy sonification is active on the output: // use device for strategy sonification // 4: the strategy "respectful" sonification is active on the output: // use device for strategy "respectful" sonification // 5: the strategy media is active on the output: // use device for strategy media // 6: the strategy DTMF is active on the output: // use device for strategy DTMF if (outputDesc->isStrategyActive(STRATEGY_ENFORCED_AUDIBLE)) { device = getDeviceForStrategy(STRATEGY_ENFORCED_AUDIBLE, fromCache); } else if (isInCall() || outputDesc->isStrategyActive(STRATEGY_PHONE)) { device = getDeviceForStrategy(STRATEGY_PHONE, fromCache); } else if (outputDesc->isStrategyActive(STRATEGY_SONIFICATION)) { device = getDeviceForStrategy(STRATEGY_SONIFICATION, fromCache); } else if (outputDesc->isStrategyActive(STRATEGY_SONIFICATION_RESPECTFUL)) { device = getDeviceForStrategy(STRATEGY_SONIFICATION_RESPECTFUL, fromCache); } else if (outputDesc->isStrategyActive(STRATEGY_MEDIA)) { device = getDeviceForStrategy(STRATEGY_MEDIA, fromCache); } else if (outputDesc->isStrategyActive(STRATEGY_DTMF)) { device = getDeviceForStrategy(STRATEGY_DTMF, fromCache); } ALOGV("getNewDevice() selected device %x", device); return device;}uint32_t AudioPolicyManagerBase::setOutputDevice(audio_io_handle_t output, audio_devices_t device, bool force, int delayMs){ ALOGV("setOutputDevice() output %d device %04x delayMs %d", output, device, delayMs); AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output); AudioParameter param; uint32_t muteWaitMs; if (outputDesc->isDuplicated()) { muteWaitMs = setOutputDevice(outputDesc->mOutput1->mId, device, force, delayMs); muteWaitMs += setOutputDevice(outputDesc->mOutput2->mId, device, force, delayMs); return muteWaitMs; } // no need to proceed if new device is not AUDIO_DEVICE_NONE and not supported by current // output profile if ((device != AUDIO_DEVICE_NONE) && ((device & outputDesc->mProfile->mSupportedDevices) == 0)) { return 0; } // filter devices according to output selected device = (audio_devices_t)(device & outputDesc->mProfile->mSupportedDevices); audio_devices_t prevDevice = outputDesc->mDevice; ALOGV("setOutputDevice() prevDevice %04x", prevDevice); // 将输出线程的当前输出设备设置为该设备 if (device != AUDIO_DEVICE_NONE) { outputDesc->mDevice = device; } muteWaitMs = checkDeviceMuteStrategies(outputDesc, prevDevice, delayMs); // Do not change the routing if: // - the requested device is AUDIO_DEVICE_NONE // - the requested device is the same as current device and force is not specified. // Doing this check here allows the caller to call setOutputDevice() without conditions if ((device == AUDIO_DEVICE_NONE || device == prevDevice) && !force) { ALOGV("setOutputDevice() setting same device %04x or null device for output %d", device, output); return muteWaitMs; } ALOGV("setOutputDevice() changing device"); // do the routing param.addInt(String8(AudioParameter::keyRouting), (int)device); mpClientInterface->setParameters(output, param.toString(), delayMs); // update stream volumes according to new device applyStreamVolumes(output, device, delayMs); return muteWaitMs;}status_t AudioFlinger::setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs){ ALOGV("setParameters(): io %d, keyvalue %s, calling pid %d", ioHandle, keyValuePairs.string(), IPCThreadState::self()->getCallingPid()); // check calling permissions if (!settingsAllowed()) { return PERMISSION_DENIED; } // ioHandle == 0 means the parameters are global to the audio hardware interface if (ioHandle == 0) { Mutex::Autolock _l(mLock); status_t final_result = NO_ERROR; { AutoMutex lock(mHardwareLock); mHardwareStatus = AUDIO_HW_SET_PARAMETER; for (size_t i = 0; i < mAudioHwDevs.size(); i++) { audio_hw_device_t *dev = mAudioHwDevs.valueAt(i)->hwDevice(); status_t result = dev->set_parameters(dev, keyValuePairs.string()); final_result = result ?: final_result; } mHardwareStatus = AUDIO_HW_IDLE; } // disable AEC and NS if the device is a BT SCO headset supporting those pre processings AudioParameter param = AudioParameter(keyValuePairs); String8 value; if (param.get(String8(AUDIO_PARAMETER_KEY_BT_NREC), value) == NO_ERROR) { bool btNrecIsOff = (value == AUDIO_PARAMETER_VALUE_OFF); if (mBtNrecIsOff != btNrecIsOff) { for (size_t i = 0; i < mRecordThreads.size(); i++) { sp<RecordThread> thread = mRecordThreads.valueAt(i); audio_devices_t device = thread->inDevice(); bool suspend = audio_is_bluetooth_sco_device(device) && btNrecIsOff; // collect all of the thread's session IDs KeyedVector<int, bool> ids = thread->sessionIds(); // suspend effects associated with those session IDs for (size_t j = 0; j < ids.size(); ++j) { int sessionId = ids.keyAt(j); thread->setEffectSuspended(FX_IID_AEC, suspend, sessionId); thread->setEffectSuspended(FX_IID_NS, suspend, sessionId); } } mBtNrecIsOff = btNrecIsOff; } } String8 screenState; if (param.get(String8(AudioParameter::keyScreenState), screenState) == NO_ERROR) { bool isOff = screenState == "off"; if (isOff != (AudioFlinger::mScreenState & 1)) { AudioFlinger::mScreenState = ((AudioFlinger::mScreenState & ~1) + 2) | isOff; } } return final_result; } // hold a strong ref on thread in case closeOutput() or closeInput() is called // and the thread is exited once the lock is released sp<ThreadBase> thread; { Mutex::Autolock _l(mLock); thread = checkPlaybackThread_l(ioHandle); if (thread == 0) { thread = checkRecordThread_l(ioHandle); } else if (thread == primaryPlaybackThread_l()) { // indicate output device change to all input threads for pre processing AudioParameter param = AudioParameter(keyValuePairs); int value; if ((param.getInt(String8(AudioParameter::keyRouting), value) == NO_ERROR) && (value != 0)) { for (size_t i = 0; i < mRecordThreads.size(); i++) { mRecordThreads.valueAt(i)->setParameters(keyValuePairs); } } } } if (thread != 0) { return thread->setParameters(keyValuePairs); } return BAD_VALUE;}status_t AudioFlinger::ThreadBase::setParameters(const String8& keyValuePairs){ status_t status; ALOGV("ThreadBase::setParameters() %s", keyValuePairs.string()); Mutex::Autolock _l(mLock); mNewParameters.add(keyValuePairs); mWaitWorkCV.signal(); // wait condition with timeout in case the thread loop has exited // before the request could be processed if (mParamCond.waitRelative(mLock, kSetParametersTimeoutNs) == NO_ERROR) { status = mParamStatus; mWaitWorkCV.signal(); } else { status = TIMED_OUT; } return status;}
0 0
- Audio笔记之耳机插拔检测
- Audio笔记之耳机插拔检测
- Android4.×耳机插拔检测
- Android4.×耳机插拔检测
- android 耳机插拔检测(kernel)
- android4.x 耳机插拔检测机制
- windows7下检测耳机麦克拔插
- android+耳机插拔和耳机按键检测
- 【audio】耳机插拔/线控按键识别流程
- 耳机插拔流程
- 耳机插拔流程
- Android 4.x耳机插拔检测实现方法
- Android 4.x耳机插拔检测实现方法
- Android4.2耳机插拔检测实现方法
- Android 4.x耳机插拔检测实现方法
- Android4.2耳机插拔检测实现方法
- 【TopDesk】3.1.1. 利用IMMNotificationClient实现耳机插拔检测
- usb驱动之设备插拔检测
- ncverilog和verdi结合使用dump fsdb
- 高效STL—迭代器 & 算法
- 黑马程序员——OC中字典的用法总结
- 给老板汇报技术规划的要点
- 小白马卫士之流量统计
- Audio笔记之耳机插拔检测
- Python中将生成的向量存入一个矩阵中
- 聚类分析(二)——K中心点算法(k-mediods)
- 【深入浅出ios开发】UIStoryboardSegue详解
- Linux内核中常见内存分配函数
- android handle 用法
- wxWidgets 安装
- 用“逐步排除”的方法定位Java服务线上“系统性”故障
- 程序员的“机械同感”