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中
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 makeObservedUEventList() {
List retVal = new ArrayList();
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.
* This method will cause the UEvent thread to start if this is the first
* invocation of startObserving in this process.
* Once called, the UEvent thread will call onUEvent() when an incoming
* UEvent matches the specified string.
* 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)
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& 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 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_ops
static int aps_suspend_output(void *service, audio_io_handle_t output)
{
sp 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 srcOutputs = getOutputsForDevice(oldDevice, mPreviousOutputs);
SortedVector 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 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获得设备,然后重新分配给output
audio_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 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 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 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;
}