对于耳麦的插拔,Android有两种模式,可以使用input子系统,也可以使用state dev(uevent)上报拔插操作。
输入子系统:上报开关事件(EV_SW),事件类型包括headset、headPhone、lineOut。对于输入设备都需要指定能产生同步类事件EV_SYN。对于按键事件,输入子系统还需要设置按键值的范围,但是对于开关类事件不需要设置。
switch class子系统:通过uevent向用户空间发送数据,Android中有个线程专门监听这类事件。使用switch dev子系统时,名字必须要设置为"h2w",Android系统监听/sys/class/switch/h2w这个虚拟设备。
具体使用哪种操作 取决于config_useDevInputEventForAudioJack 这个配置值,该值为true时使用input子系统, 为false时使用uevent机制。
1. 驱动程序上报音频拔插事件
xref: /frameworks/native/services/inputflinger/InputReader.cpp
void InputReader::loopOnce() {
int32_t oldGeneration;
int32_t timeoutMillis;
bool inputDevicesChanged = false;
std::vector<InputDeviceInfo> inputDevices;
{ // acquire lock
AutoMutex _l(mLock);
oldGeneration = mGeneration;
timeoutMillis = -1;
uint32_t changes = mConfigurationChangesToRefresh;
if (changes) {
mConfigurationChangesToRefresh = 0;
timeoutMillis = 0;
refreshConfigurationLocked(changes);
} else if (mNextTimeout != LLONG_MAX) {
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
timeoutMillis = toMillisecondTimeoutDelay(now, mNextTimeout);
}
} // release lock
// 监听耳机插拔事件
size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
{ // acquire lock
AutoMutex _l(mLock);
mReaderIsAliveCondition.broadcast();
// 处理插拔事件
if (count) {
processEventsLocked(mEventBuffer, count);
}
if (mNextTimeout != LLONG_MAX) {
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
if (now >= mNextTimeout) {
#if DEBUG_RAW_EVENTS
ALOGD("Timeout expired, latency=%0.3fms", (now - mNextTimeout) * 0.000001f);
#endif
mNextTimeout = LLONG_MAX;
timeoutExpiredLocked(now);
}
}
if (oldGeneration != mGeneration) {
inputDevicesChanged = true;
getInputDevicesLocked(inputDevices);
}
} // release lock
// Send out a message that the describes the changed input devices.
if (inputDevicesChanged) {
mPolicy->notifyInputDevicesChanged(inputDevices);
}
// Flush queued events out to the listener.
// This must happen outside of the lock because the listener could potentially call
// back into the InputReader's methods, such as getScanCodeState, or become blocked
// on another thread similarly waiting to acquire the InputReader lock thereby
// resulting in a deadlock. This situation is actually quite plausible because the
// listener is actually the input dispatcher, which calls into the window manager,
// which occasionally calls into the input reader.
mQueuedListener->flush();
}
在loopOnce()方法中监听耳机插拔事件,如果监听到耳机插入,则count的值会发生变化。然后调用processEventsLocked方法处理,如果没有耳机插入则休眠。
void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) {
for (const RawEvent* rawEvent = rawEvents; count;) {
int32_t type = rawEvent->type;
size_t batchSize = 1;
if (type < EventHubInterface::FIRST_SYNTHETIC_EVENT) {
int32_t deviceId = rawEvent->deviceId;
while (batchSize < count) {
if (rawEvent[batchSize].type >= EventHubInterface::FIRST_SYNTHETIC_EVENT
|| rawEvent[batchSize].deviceId != deviceId) {
break;
}
batchSize += 1;
}
#if DEBUG_RAW_EVENTS
ALOGD("BatchSize: %zu Count: %zu", batchSize, count);
#endif
processEventsForDeviceLocked(deviceId, rawEvent, batchSize);
} else {
switch (rawEvent->type) {
case EventHubInterface::DEVICE_ADDED://设备添加事件
addDeviceLocked(rawEvent->when, rawEvent->deviceId);
break;
case EventHubInterface::DEVICE_REMOVED://设备删除事件
removeDeviceLocked(rawEvent->when, rawEvent->deviceId);
break;
case EventHubInterface::FINISHED_DEVICE_SCAN://设备扫描事件
handleConfigurationChangedLocked(rawEvent->when);
break;
default:
ALOG_ASSERT(false); // can't happen
break;
}
}
count -= batchSize;
rawEvent += batchSize;
}
}
这里将设备的各种事件进行分开处理。如果事件type小于FIRST_SYNTHETIC_EVENT,那么此次不是一次设备增加/删除/扫描事件,调用processEventsForDeviceLocked方法处理本次输入事件
void InputReader::processEventsForDeviceLocked(int32_t deviceId,
const RawEvent* rawEvents, size_t count) {
ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
if (deviceIndex < 0) {
ALOGW("Discarding event for unknown deviceId %d.", deviceId);
return;
}
InputDevice* device = mDevices.valueAt(deviceIndex);
if (device->isIgnored()) {
//ALOGD("Discarding event for ignored deviceId %d.", deviceId);
return;
}
device->process(rawEvents, count);
}
根据deviceIndex从mDevices中获取对应的InputDevice设备对象,然后调用process进行处理rawEvents。此处调用的process是InputDevice::process
void InputDevice::process(const RawEvent* rawEvents, size_t count) {
// Process all of the events in order for each mapper.
// We cannot simply ask each mapper to process them in bulk because mappers may
// have side-effects that must be interleaved. For example, joystick movement events and
// gamepad button presses are handled by different mappers but they should be dispatched
// in the order received.
// for循环依次处理count个rawEvents。
for (const RawEvent* rawEvent = rawEvents; count != 0; rawEvent++) {
#if DEBUG_RAW_EVENTS
ALOGD("Input event: device=%d type=0x%04x code=0x%04x value=0x%08x when=%" PRId64,
rawEvent->deviceId, rawEvent->type, rawEvent->code, rawEvent->value,
rawEvent->when);
#endif
if (mDropUntilNextSync) {
if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
mDropUntilNextSync = false;
#if DEBUG_RAW_EVENTS
ALOGD("Recovered from input event buffer overrun.");
#endif
} else {
#if DEBUG_RAW_EVENTS
ALOGD("Dropped input event while waiting for next input sync.");
#endif
}
} else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_DROPPED) {
ALOGI("Detected input event buffer overrun for device %s.", getName().c_str());
mDropUntilNextSync = true;
reset(rawEvent->when);
} else {
for (InputMapper* mapper : mMappers) {
mapper->process(rawEvent);
}
}
--count;
}
}
for循环依次处理count个rawEvents。
mDropUntilNextSync到下一次同步前的都扔掉,收到rawEvent->type == EV_SYN && rawEvent->code == SYN_DROPPED时,该标记会置位。如果底层client的循环buffer出现问题的时候会发送这个code,收到此code,要一直等到下一次的rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT才能复位。一般都是走最后一个else判断。mapper->process是
void SwitchInputMapper::process(const RawEvent* rawEvent) {
switch (rawEvent->type) {
case EV_SW:
processSwitch(rawEvent->code, rawEvent->value);
break;
case EV_SYN:
if (rawEvent->code == SYN_REPORT) {
sync(rawEvent->when);
}
}
}
根据上报事件进行处理,EV_SW:开关类事件;EV_SYN:同步类事件
void SwitchInputMapper::processSwitch(int32_t switchCode, int32_t switchValue) {
if (switchCode >= 0 && switchCode < 32) {
if (switchValue) {
mSwitchValues |= 1 << switchCode;
} else {
mSwitchValues &= ~(1 << switchCode);
}
mUpdatedSwitchMask |= 1 << switchCode;
}
}
通过mSwitchValues的值进行状态存储。mSwitchValues |= 1 << switchCode;按下则记录switchCode值。mSwitchValues &= ~(1 << switchCode);松开则清除switchCode值。mUpdatedSwitchMask |= 1 << switchCode;将switchCode记录在mUpdatedSwitchMask里面。
void SwitchInputMapper::sync(nsecs_t when) {
if (mUpdatedSwitchMask) {
uint32_t updatedSwitchValues = mSwitchValues & mUpdatedSwitchMask;
NotifySwitchArgs args(mContext->getNextSequenceNum(), when, 0, updatedSwitchValues,
mUpdatedSwitchMask);
getListener()->notifySwitch(&args);
mUpdatedSwitchMask = 0;
}
}
这里的getListener()->notifySwitch(&args)实际上就是InputDispatcher的notifySwitch方法。
void InputDispatcher::notifySwitch(const NotifySwitchArgs* args) {
#if DEBUG_INBOUND_EVENT_DETAILS
ALOGD("notifySwitch - eventTime=%" PRId64 ", policyFlags=0x%x, switchValues=0x%08x, "
"switchMask=0x%08x",
args->eventTime, args->policyFlags, args->switchValues, args->switchMask);
#endif
uint32_t policyFlags = args->policyFlags;
policyFlags |= POLICY_FLAG_TRUSTED;
mPolicy->notifySwitch(args->eventTime,
args->switchValues, args->switchMask, policyFlags);
}
xref: /frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp
void NativeInputManager::notifySwitch(nsecs_t when,
uint32_t switchValues, uint32_t switchMask, uint32_t /* policyFlags */) {
#if DEBUG_INPUT_DISPATCHER_POLICY
ALOGD("notifySwitch - when=%lld, switchValues=0x%08x, switchMask=0x%08x, policyFlags=0x%x",
when, switchValues, switchMask, policyFlags);
#endif
ATRACE_CALL();
JNIEnv* env = jniEnv();
env->CallVoidMethod(mServiceObj, gServiceClassInfo.notifySwitch,
when, switchValues, switchMask);
checkAndClearExceptionFromCallback(env, "notifySwitch");
}
env->CallVoidMethod调用java中的同名函数
xref: /frameworks/base/services/core/java/com/android/server/input/InputManagerService.java
// Native callback.
private void notifySwitch(long whenNanos, int switchValues, int switchMask) {
if (DEBUG) {
Slog.d(TAG, "notifySwitch: values=" + Integer.toHexString(switchValues)
+ ", mask=" + Integer.toHexString(switchMask));
}
if ((switchMask & SW_LID_BIT) != 0) {
final boolean lidOpen = ((switchValues & SW_LID_BIT) == 0);
mWindowManagerCallbacks.notifyLidSwitchChanged(whenNanos, lidOpen);
}
if ((switchMask & SW_CAMERA_LENS_COVER_BIT) != 0) {
final boolean lensCovered = ((switchValues & SW_CAMERA_LENS_COVER_BIT) != 0);
mWindowManagerCallbacks.notifyCameraLensCoverSwitchChanged(whenNanos, lensCovered);
}
if (mUseDevInputEventForAudioJack && (switchMask & SW_JACK_BITS) != 0) {
mWiredAccessoryCallbacks.notifyWiredAccessoryChanged(whenNanos, switchValues,
switchMask);
}
if ((switchMask & SW_TABLET_MODE_BIT) != 0) {
SomeArgs args = SomeArgs.obtain();
args.argi1 = (int) (whenNanos & 0xFFFFFFFF);
args.argi2 = (int) (whenNanos >> 32);
args.arg1 = Boolean.valueOf((switchValues & SW_TABLET_MODE_BIT) != 0);
mHandler.obtainMessage(MSG_DELIVER_TABLET_MODE_CHANGED,
args).sendToTarget();
}
}
调用到mWiredAccessoryCallbacks中的notifyWiredAccessoryChanged。mUseDevInputEventForAudioJack就是来自config.xml文件配置,为true才会选择输入子系统。
xref: /frameworks/base/services/core/java/com/android/server/WiredAccessoryManager.java
@Override
public void notifyWiredAccessoryChanged(long whenNanos, int switchValues, int switchMask) {
if (LOG) {
Slog.v(TAG, "notifyWiredAccessoryChanged: when=" + whenNanos
+ " bits=" + switchCodeToString(switchValues, switchMask)
+ " mask=" + Integer.toHexString(switchMask));
}
synchronized (mLock) {
int headset;
mSwitchValues = (mSwitchValues & ~switchMask) | switchValues;
switch (mSwitchValues &
(SW_HEADPHONE_INSERT_BIT | SW_MICROPHONE_INSERT_BIT | SW_LINEOUT_INSERT_BIT)) {
case 0:
headset = 0;
break;
case SW_HEADPHONE_INSERT_BIT:
headset = BIT_HEADSET_NO_MIC;
break;
case SW_LINEOUT_INSERT_BIT:
headset = BIT_LINEOUT;
break;
case SW_HEADPHONE_INSERT_BIT | SW_MICROPHONE_INSERT_BIT:
headset = BIT_HEADSET;
break;
case SW_MICROPHONE_INSERT_BIT:
headset = BIT_HEADSET;
break;
default:
headset = 0;
break;
}
// 上报事件的两条分支(input和Switch class)在这里汇合了
updateLocked(NAME_H2W,
(mHeadsetState & ~(BIT_HEADSET | BIT_HEADSET_NO_MIC | BIT_LINEOUT)) | headset);
}
}
根据驱动程序的上传mSwitchValues值来确定headset。通过判断得出一个新的headset状态,再根据headset状态去设置outDevice和inDevice的值,从而通过AudioManager设置状态
xref: /frameworks/base/services/core/java/com/android/server/WiredAccessoryManager.java
private void updateLocked(String newName, int newState) {
// Retain only relevant bits
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;
boolean usbStateChange = true;
if (LOG) {
Slog.v(TAG, "newName=" + newName
+ " newState=" + newState
+ " headsetState=" + headsetState
+ " prev headsetState=" + mHeadsetState);
}
if (mHeadsetState == headsetState) {
Log.e(TAG, "No state change.");
return;
}
// reject all suspect transitions: only accept state changes from:
// - a: 0 headset to 1 headset
// - b: 1 headset to 0 headset
if (h2w_headset == (BIT_HEADSET | BIT_HEADSET_NO_MIC | BIT_LINEOUT)) {
Log.e(TAG, "Invalid combination, unsetting h2w flag");
h2wStateChange = false;
}
// - c: 0 usb headset to 1 usb headset
// - d: 1 usb headset to 0 usb headset
if (usb_headset_anlg == BIT_USB_HEADSET_ANLG && usb_headset_dgtl == BIT_USB_HEADSET_DGTL) {
Log.e(TAG, "Invalid combination, unsetting usb flag");
usbStateChange = false;
}
if (!h2wStateChange && !usbStateChange) {
Log.e(TAG, "invalid transition, returning ...");
return;
}
mWakeLock.acquire();
// 发送message消息
Log.i(TAG, "MSG_NEW_DEVICE_STATE");
Message msg = mHandler.obtainMessage(MSG_NEW_DEVICE_STATE, headsetState,
mHeadsetState, "");
mHandler.sendMessage(msg);
// 更新mHeadsetState状态
mHeadsetState = headsetState;
}
更新耳机状态,并发送message消息MSG_NEW_DEVICE_STATE
private final Handler mHandler = new Handler(Looper.myLooper(), null, true) {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_NEW_DEVICE_STATE:
setDevicesState(msg.arg1, msg.arg2, (String) msg.obj);
mWakeLock.release();
break;
case MSG_SYSTEM_READY:
onSystemReady();
mWakeLock.release();
break;
}
}
};
调用setDevicesState处理消息
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;
}
}
}
}
调用setDeviceStateLocked方法
private void setDeviceStateLocked(int headset,
int headsetState, int prevHeadsetState, String headsetName) {
if ((headsetState & headset) != (prevHeadsetState & headset)) {
int outDevice = 0;
int inDevice = 0;
int state;
if ((headsetState & headset) != 0) {
state = 1;
} else {
state = 0;
}
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;
} else if (headset == BIT_USB_HEADSET_ANLG) {
outDevice = AudioManager.DEVICE_OUT_ANLG_DOCK_HEADSET;
} else if (headset == BIT_USB_HEADSET_DGTL) {
outDevice = AudioManager.DEVICE_OUT_DGTL_DOCK_HEADSET;
} else if (headset == BIT_HDMI_AUDIO) {
outDevice = AudioManager.DEVICE_OUT_HDMI;
} else {
Slog.e(TAG, "setDeviceState() invalid headset type: " + headset);
return;
}
if (LOG) {
Slog.v(TAG, "headsetName: " + headsetName +
(state == 1 ? " connected" : " disconnected"));
}
if (outDevice != 0) {
mAudioManager.setWiredDeviceConnectionState(outDevice, state, "", headsetName);
}
if (inDevice != 0) {
mAudioManager.setWiredDeviceConnectionState(inDevice, state, "", headsetName);
}
}
}
根据headset的状态去设置outDevice和inDevice的值,从而通过AudioManager设置有限设备的连接状态
Andorid系统支持的外设设备是通过一个整型变量去针对不同的音频外设进行标志与表示。任何可用的音频外设在这个整型变量中用1个二进制的标志为去表示。
xref: /frameworks/base/media/java/android/media/AudioManager.java
public void setWiredDeviceConnectionState(int type, int state, String address, String name) {
final IAudioService service = getService();
try {
service.setWiredDeviceConnectionState(type, state, address, name,
mApplicationContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
调用AudioService的setWiredDeviceConnectionState方法
xref: /frameworks/base/services/core/java/com/android/server/audio/AudioService.java
public void setWiredDeviceConnectionState(int type,
@ConnectionState int state, String address, String name,
String caller) {
if (state != CONNECTION_STATE_CONNECTED
&& state != CONNECTION_STATE_DISCONNECTED) {
throw new IllegalArgumentException("Invalid state " + state);
}
mDeviceBroker.setWiredDeviceConnectionState(type, state, address, name, caller);
}
调用AudioDeviceBroker的setWiredDeviceConnectionState方法
xref: /frameworks/base/services/core/java/com/android/server/audio/AudioDeviceBroker.java
/*package*/ void setWiredDeviceConnectionState(int type,
@AudioService.ConnectionState int state, String address, String name,
String caller) {
//TODO move logging here just like in setBluetooth* methods
synchronized (mDeviceStateLock) {
mDeviceInventory.setWiredDeviceConnectionState(type, state, address, name, caller);
}
}
调用AudioDeviceInventory的setWiredDeviceConnectionState方法
xref: /frameworks/base/services/core/java/com/android/server/audio/AudioDeviceInventory.java
/*package*/ int setWiredDeviceConnectionState(int type, @AudioService.ConnectionState int state,
String address, String name, String caller) {
synchronized (mConnectedDevices) {
// 指定一个延时时间后又把消息放到一个消息队列中
int delay = checkSendBecomingNoisyIntentInt(type, state, AudioSystem.DEVICE_NONE);
mDeviceBroker.postSetWiredDeviceConnectionState(
new WiredDeviceConnectionState(type, state, address, name, caller),
delay);
return delay;
}
}
指定一个延时时间后又把消息放到一个消息队列中
xref: /frameworks/base/services/core/java/com/android/server/audio/AudioDeviceBroker.java
/*package*/ void postSetWiredDeviceConnectionState(
AudioDeviceInventory.WiredDeviceConnectionState connectionState, int delay) {
sendLMsg(MSG_L_SET_WIRED_DEVICE_CONNECTION_STATE, SENDMSG_QUEUE, connectionState, delay);
}
根据指定的delay时间发送消息
private class BrokerHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_RESTORE_DEVICES:
synchronized (mDeviceStateLock) {
mDeviceInventory.onRestoreDevices();
mBtHelper.onAudioServerDiedRestoreA2dp();
}
break;
case MSG_L_SET_WIRED_DEVICE_CONNECTION_STATE:
synchronized (mDeviceStateLock) {
mDeviceInventory.onSetWiredDeviceConnectionState(
(AudioDeviceInventory.WiredDeviceConnectionState) msg.obj);
}
break;
..........................................................................
default:
Log.wtf(TAG, "Invalid message " + msg.what);
}
...........................................................................
}
}
xref: /frameworks/base/services/core/java/com/android/server/audio/AudioDeviceInventory.java
/*package*/ void onSetWiredDeviceConnectionState(
AudioDeviceInventory.WiredDeviceConnectionState wdcs) {
AudioService.sDeviceLogger.log(new AudioServiceEvents.WiredDevConnectEvent(wdcs));
synchronized (mConnectedDevices) {
// 当拔出普通耳机的时候如果连接了蓝牙耳机,会优先将音频输出到蓝牙耳机
if ((wdcs.mState == AudioService.CONNECTION_STATE_DISCONNECTED)
&& ((wdcs.mType & DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG) != 0)) {
mDeviceBroker.setBluetoothA2dpOnInt(true,
"onSetWiredDeviceConnectionState state DISCONNECTED");
}
// 确保设备连接并向下设置设备支持的参数
if (!handleDeviceConnection(wdcs.mState == AudioService.CONNECTION_STATE_CONNECTED,
wdcs.mType, wdcs.mAddress, wdcs.mName)) {
// change of connection state failed, bailout
return;
}
if (wdcs.mState != AudioService.CONNECTION_STATE_DISCONNECTED) {
if ((wdcs.mType & DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG) != 0) {
mDeviceBroker.setBluetoothA2dpOnInt(false,
"onSetWiredDeviceConnectionState state not DISCONNECTED");
}
mDeviceBroker.checkMusicActive(wdcs.mType, wdcs.mCaller);
}
if (wdcs.mType == AudioSystem.DEVICE_OUT_HDMI) {
mDeviceBroker.checkVolumeCecOnHdmiConnection(wdcs.mState, wdcs.mCaller);
}
// 发送Intent去通知音频外设的状态变化
sendDeviceConnectionIntent(wdcs.mType, wdcs.mState, wdcs.mAddress, wdcs.mName);
// 更新audio路由
updateAudioRoutes(wdcs.mType, wdcs.mState);
}
}
handleDeviceConnection:操作一个负责对mConnectedDevices更新并通过AudioSystem去设置值进底层。
sendDeviceConnectionIntent:通过发送Intent去通知音频外设的状态变化。
updateAudioRoutes: 更新audio路由。
private void sendDeviceConnectionIntent(int device, int state, String address,
String deviceName) {
if (AudioService.DEBUG_DEVICES) {
Slog.i(TAG, "sendDeviceConnectionIntent(dev:0x" + Integer.toHexString(device)
+ " state:0x" + Integer.toHexString(state) + " address:" + address
+ " name:" + deviceName + ");");
}
Intent intent = new Intent();
switch(device) {
case AudioSystem.DEVICE_OUT_WIRED_HEADSET:
intent.setAction(Intent.ACTION_HEADSET_PLUG);
intent.putExtra("microphone", 1);
break;
case AudioSystem.DEVICE_OUT_WIRED_HEADPHONE:
case AudioSystem.DEVICE_OUT_LINE:
intent.setAction(Intent.ACTION_HEADSET_PLUG);
intent.putExtra("microphone", 0);
break;
case AudioSystem.DEVICE_OUT_USB_HEADSET:
intent.setAction(Intent.ACTION_HEADSET_PLUG);
intent.putExtra("microphone",
AudioSystem.getDeviceConnectionState(AudioSystem.DEVICE_IN_USB_HEADSET, "")
== AudioSystem.DEVICE_STATE_AVAILABLE ? 1 : 0);
break;
case AudioSystem.DEVICE_IN_USB_HEADSET:
if (AudioSystem.getDeviceConnectionState(AudioSystem.DEVICE_OUT_USB_HEADSET, "")
== AudioSystem.DEVICE_STATE_AVAILABLE) {
intent.setAction(Intent.ACTION_HEADSET_PLUG);
intent.putExtra("microphone", 1);
} else {
// do not send ACTION_HEADSET_PLUG when only the input side is seen as changing
return;
}
break;
case AudioSystem.DEVICE_OUT_HDMI:
case AudioSystem.DEVICE_OUT_HDMI_ARC:
configureHdmiPlugIntent(intent, state);
break;
}
if (intent.getAction() == null) {
return;
}
intent.putExtra(CONNECT_INTENT_KEY_STATE, state);
intent.putExtra(CONNECT_INTENT_KEY_ADDRESS, address);
intent.putExtra(CONNECT_INTENT_KEY_PORT_NAME, deviceName);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
final long ident = Binder.clearCallingIdentity();
try {
ActivityManager.broadcastStickyIntent(intent, UserHandle.USER_CURRENT);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
发送广播
xref: /frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
switch (action) {
case AudioManager.RINGER_MODE_CHANGED_ACTION:
case AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION:
updateVolumeZen();
break;
case TelephonyIntents.ACTION_SIM_STATE_CHANGED:
// Avoid rebroadcast because SysUI is direct boot aware.
if (intent.getBooleanExtra(TelephonyIntents.EXTRA_REBROADCAST_ON_UNLOCK,
false)) {
break;
}
updateSimState(intent);
break;
case TelecomManager.ACTION_CURRENT_TTY_MODE_CHANGED:
updateTTY(intent.getIntExtra(TelecomManager.EXTRA_CURRENT_TTY_MODE,
TelecomManager.TTY_MODE_OFF));
break;
case Intent.ACTION_MANAGED_PROFILE_AVAILABLE:
case Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE:
case Intent.ACTION_MANAGED_PROFILE_REMOVED:
updateManagedProfile();
break;
// 接收到ACTION_HEADSET_PLUG广播之后决定是否显示耳机图标
case AudioManager.ACTION_HEADSET_PLUG:
updateHeadsetPlug(intent);
break;
}
}
};
接收到ACTION_HEADSET_PLUG广播之后决定是否显示耳机图标
private void updateHeadsetPlug(Intent intent) {
boolean connected = intent.getIntExtra("state", 0) != 0;
boolean hasMic = intent.getIntExtra("microphone", 0) != 0;
if (connected) {
String contentDescription = mContext.getString(hasMic
? R.string.accessibility_status_bar_headset
: R.string.accessibility_status_bar_headphones);
mIconController.setIcon(mSlotHeadset, hasMic ? R.drawable.stat_sys_headset_mic
: R.drawable.stat_sys_headset, contentDescription);
mIconController.setIconVisibility(mSlotHeadset, true);
} else {
mIconController.setIconVisibility(mSlotHeadset, false);
}
}
2. 声音输出通道的选择
xref: /frameworks/base/services/core/java/com/android/server/audio/AudioDeviceInventory.java
/*package*/ boolean handleDeviceConnection(boolean connect, int device, String address,
String deviceName) {
if (AudioService.DEBUG_DEVICES) {
Slog.i(TAG, "handleDeviceConnection(" + connect + " dev:"
+ Integer.toHexString(device) + " address:" + address
+ " name:" + deviceName + ")");
}
synchronized (mConnectedDevices) {
final String deviceKey = DeviceInfo.makeDeviceListKey(device, address);
if (AudioService.DEBUG_DEVICES) {
Slog.i(TAG, "deviceKey:" + deviceKey);
}
DeviceInfo di = mConnectedDevices.get(deviceKey);
boolean isConnected = di != null;
if (AudioService.DEBUG_DEVICES) {
Slog.i(TAG, "deviceInfo:" + di + " is(already)Connected:" + isConnected);
}
if (connect && !isConnected) {// 外设被插入,通过AudioSystem将状态设置到底层的AudioPolicyService
final int res = AudioSystem.setDeviceConnectionState(device,
AudioSystem.DEVICE_STATE_AVAILABLE, address, deviceName,
AudioSystem.AUDIO_FORMAT_DEFAULT);
if (res != AudioSystem.AUDIO_STATUS_OK) {
Slog.e(TAG, "not connecting device 0x" + Integer.toHexString(device)
+ " due to command error " + res);
return false;
}
mConnectedDevices.put(deviceKey, new DeviceInfo(
device, deviceName, address, AudioSystem.AUDIO_FORMAT_DEFAULT));
mDeviceBroker.postAccessoryPlugMediaUnmute(device);
return true;
} else if (!connect && isConnected) {// 外设被拔出,通过AudioSystem将状态设置到底层的AudioPolicyService
AudioSystem.setDeviceConnectionState(device,
AudioSystem.DEVICE_STATE_UNAVAILABLE, address, deviceName,
AudioSystem.AUDIO_FORMAT_DEFAULT);
// always remove even if disconnection failed
mConnectedDevices.remove(deviceKey);
return true;
}
Log.w(TAG, "handleDeviceConnection() failed, deviceKey=" + deviceKey
+ ", deviceSpec=" + di + ", connect=" + connect);
}
return false;
}
handleDeviceConnection它会更新底层的可用设备列表,并且触发设备切换
xref: /frameworks/av/media/libaudioclient/AudioSystem.cpp
status_t AudioSystem::setDeviceConnectionState(audio_devices_t device,
audio_policy_dev_state_t state,
const char *device_address,
const char *device_name,
audio_format_t encodedFormat)
{
const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
const char *address = "";
const char *name = "";
if (aps == 0) return PERMISSION_DENIED;
if (device_address != NULL) {
address = device_address;
}
if (device_name != NULL) {
name = device_name;
}
return aps->setDeviceConnectionState(device, state, address, name, encodedFormat);
}
调用AudioPolicyInterfaceImpl.cpp的setDeviceConnectionState
xref: /frameworks/av/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
status_t AudioPolicyService::setDeviceConnectionState(audio_devices_t device,
audio_policy_dev_state_t state,
const char *device_address,
const char *device_name,
audio_format_t encodedFormat)
{
if (mAudioPolicyManager == NULL) {
return NO_INIT;
}
if (!settingsAllowed()) {
return PERMISSION_DENIED;
}
if (state != AUDIO_POLICY_DEVICE_STATE_AVAILABLE &&
state != AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE) {
return BAD_VALUE;
}
ALOGV("setDeviceConnectionState()");
Mutex::Autolock _l(mLock);
AutoCallerClear acc;
return mAudioPolicyManager->setDeviceConnectionState(device, state,
device_address, device_name, encodedFormat);
}
xref: /frameworks/av/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
status_t AudioPolicyManager::setDeviceConnectionState(audio_devices_t device,
audio_policy_dev_state_t state,
const char *device_address,
const char *device_name,
audio_format_t encodedFormat)
{
status_t status = setDeviceConnectionStateInt(device, state, device_address,
device_name, encodedFormat);
nextAudioPortGeneration();
return status;
}
.........................................................................................
status_t AudioPolicyManager::setDeviceConnectionStateInt(audio_devices_t deviceType,
audio_policy_dev_state_t state,
const char *device_address,
const char *device_name,
audio_format_t encodedFormat)
{
ALOGV("setDeviceConnectionStateInt() device: 0x%X, state %d, address %s name %s format 0x%X",
deviceType, state, device_address, device_name, encodedFormat);
// connect/disconnect only 1 device at a time
if (!audio_is_output_device(deviceType) && !audio_is_input_device(deviceType)) return BAD_VALUE;
sp<DeviceDescriptor> device =
mHwModules.getDeviceDescriptor(deviceType, device_address, device_name, encodedFormat,
state == AUDIO_POLICY_DEVICE_STATE_AVAILABLE);
if (device == 0) {
return INVALID_OPERATION;
}
// handle output devices
if (audio_is_output_device(deviceType)) {// 判断deviceType是不是输出设备类型
SortedVector <audio_io_handle_t> outputs;
ssize_t index = mAvailableOutputDevices.indexOf(device);
// 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 AUDIO_POLICY_DEVICE_STATE_AVAILABLE: {
if (index >= 0) {// 如果该设备存在,则直接返回。否则添加一个新的
ALOGW("%s() device already connected: %s", __func__, device->toString().c_str());
return INVALID_OPERATION;
}
ALOGV("%s() connecting device %s format %x",
__func__, device->toString().c_str(), encodedFormat);
// register new device as available
if (mAvailableOutputDevices.add(device) < 0) {// 添加到可用输出设备
return NO_MEMORY;
}
// Before checking outputs, broadcast connect event to allow HAL to retrieve dynamic
// parameters on newly connected devices (instead of opening the outputs...)
broadcastDeviceConnectionState(device, state);
// 针对该设备打开新的output并创建新的playbackThread
if (checkOutputsForDevice(device, state, outputs) != NO_ERROR) {
mAvailableOutputDevices.remove(device);
mHwModules.cleanUpForDevice(device);
broadcastDeviceConnectionState(device, AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE);
return INVALID_OPERATION;
}
// outputs should never be empty here
ALOG_ASSERT(outputs.size() != 0, "setDeviceConnectionState():"
"checkOutputsForDevice() returned no outputs but status OK");
ALOGV("%s() checkOutputsForDevice() returned %zu outputs", __func__, outputs.size());
} break;
// handle output device disconnection
..............................................................................................
// 对所有的strategy进行分组,判断是否需要迁移到新的output
if (doCheckForDeviceAndOutputChanges) {
checkForDeviceAndOutputChanges(checkCloseOutputs);
} else {
checkCloseOutputs();
}
..............................................................................................
return NO_ERROR;
} // end if is output device
..............................................................................................
return BAD_VALUE;
}
接下来先对checkOutputsForDevice进行分析
status_t AudioPolicyManager::checkOutputsForDevice(const sp<DeviceDescriptor>& device,
audio_policy_dev_state_t state,
SortedVector<audio_io_handle_t>& outputs)
{
audio_devices_t deviceType = device->type();
const String8 &address = device->address();
sp<SwAudioOutputDescriptor> desc;
if (audio_device_is_digital(deviceType)) {
// erase all current sample rates, formats and channel masks
device->clearAudioProfiles();
}
if (state == AUDIO_POLICY_DEVICE_STATE_AVAILABLE) {
// first list already open outputs that can be routed to this device
for (size_t i = 0; i < mOutputs.size(); i++) {
desc = mOutputs.valueAt(i);
if (!desc->isDuplicated() && desc->supportsDevice(device)
&& desc->deviceSupportsEncodedFormats(deviceType)) {
ALOGV("checkOutputsForDevice(): adding opened output %d on device %s",
mOutputs.keyAt(i), device->toString().c_str());
outputs.add(mOutputs.keyAt(i));
}
}
// then look for output profiles that can be routed to this device
SortedVector< sp<IOProfile> > profiles;
for (const auto& hwModule : mHwModules) {
for (size_t j = 0; j < hwModule->getOutputProfiles().size(); j++) {
sp<IOProfile> profile = hwModule->getOutputProfiles()[j];
if (profile->supportsDevice(device)) {
profiles.add(profile);
ALOGV("checkOutputsForDevice(): adding profile %zu from module %s",
j, hwModule->getName());
}
}
}
ALOGV(" found %zu profiles, %zu outputs", profiles.size(), outputs.size());
if (profiles.isEmpty() && outputs.isEmpty()) {
ALOGW("checkOutputsForDevice(): No output available for device %04x", deviceType);
return BAD_VALUE;
}
// open outputs for matching profiles if needed. Direct outputs are also opened to
// query for dynamic parameters and will be closed later by setDeviceConnectionState()
for (ssize_t profile_index = 0; profile_index < (ssize_t)profiles.size(); profile_index++) {
sp<IOProfile> profile = profiles[profile_index];
// nothing to do if one output is already opened for this profile
size_t j;
for (j = 0; j < outputs.size(); j++) {
desc = mOutputs.valueFor(outputs.itemAt(j));
if (!desc->isDuplicated() && desc->mProfile == profile) {
// matching profile: save the sample rates, format and channel masks supported
// by the profile in our device descriptor
if (audio_device_is_digital(deviceType)) {
device->importAudioPort(profile);
}
break;
}
}
if (j != outputs.size()) {
continue;
}
if (!profile->canOpenNewIo()) {
ALOGW("Max Output number %u already opened for this profile %s",
profile->maxOpenCount, profile->getTagName().c_str());
continue;
}
ALOGV("opening output for device %08x with params %s profile %p name %s",
deviceType, address.string(), profile.get(), profile->getName().string());
desc = new SwAudioOutputDescriptor(profile, mpClientInterface);
audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
status_t status = desc->open(nullptr, DeviceVector(device),
AUDIO_STREAM_DEFAULT, AUDIO_OUTPUT_FLAG_NONE, &output);
if (status == NO_ERROR) {
// Here is where the out_set_parameters() for card & device gets called
if (!address.isEmpty()) {
char *param = audio_device_address_to_parameter(deviceType, address);
mpClientInterface->setParameters(output, String8(param));
free(param);
}
updateAudioProfiles(device, output, profile->getAudioProfiles());
if (!profile->hasValidAudioProfile()) {
ALOGW("checkOutputsForDevice() missing param");
desc->close();
output = AUDIO_IO_HANDLE_NONE;
} else if (profile->hasDynamicAudioProfile()) {
desc->close();
output = AUDIO_IO_HANDLE_NONE;
audio_config_t config = AUDIO_CONFIG_INITIALIZER;
profile->pickAudioProfile(
config.sample_rate, config.channel_mask, config.format);
config.offload_info.sample_rate = config.sample_rate;
config.offload_info.channel_mask = config.channel_mask;
config.offload_info.format = config.format;
status_t status = desc->open(&config, DeviceVector(device),
AUDIO_STREAM_DEFAULT,
AUDIO_OUTPUT_FLAG_NONE, &output);
if (status != NO_ERROR) {
output = AUDIO_IO_HANDLE_NONE;
}
}
if (output != AUDIO_IO_HANDLE_NONE) {
addOutput(output, desc);
if (device_distinguishes_on_address(deviceType) && address != "0") {
sp<AudioPolicyMix> policyMix;
if (mPolicyMixes.getAudioPolicyMix(deviceType, address, policyMix)
== NO_ERROR) {
policyMix->setOutput(desc);
desc->mPolicyMix = policyMix;
} else {
ALOGW("checkOutputsForDevice() cannot find policy for address %s",
address.string());
}
} else if (((desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) == 0) &&
hasPrimaryOutput()) {
// no duplicated output for direct outputs and
// outputs used by dynamic policy mixes
audio_io_handle_t duplicatedOutput = AUDIO_IO_HANDLE_NONE;
//TODO: configure audio effect output stage here
// open a duplicating output thread for the new output and the primary output
sp<SwAudioOutputDescriptor> dupOutputDesc =
new SwAudioOutputDescriptor(NULL, mpClientInterface);
status_t status = dupOutputDesc->openDuplicating(mPrimaryOutput, desc,
&duplicatedOutput);
if (status == NO_ERROR) {
// add duplicated output descriptor
addOutput(duplicatedOutput, dupOutputDesc);
} else {
ALOGW("checkOutputsForDevice() could not open dup output for %d and %d",
mPrimaryOutput->mIoHandle, output);
desc->close();
removeOutput(output);
nextAudioPortGeneration();
output = AUDIO_IO_HANDLE_NONE;
}
}
}
} else {
output = AUDIO_IO_HANDLE_NONE;
}
if (output == AUDIO_IO_HANDLE_NONE) {
ALOGW("checkOutputsForDevice() could not open output for device %x", deviceType);
profiles.removeAt(profile_index);
profile_index--;
} else {
outputs.add(output);
// Load digital format info only for digital devices
if (audio_device_is_digital(deviceType)) {
device->importAudioPort(profile);
}
if (device_distinguishes_on_address(deviceType)) {
ALOGV("checkOutputsForDevice(): setOutputDevices %s",
device->toString().c_str());
setOutputDevices(desc, DeviceVector(device), true/*force*/, 0/*delay*/,
NULL/*patch handle*/);
}
ALOGV("checkOutputsForDevice(): adding output %d", output);
}
}
if (profiles.isEmpty()) {
ALOGW("checkOutputsForDevice(): No output available for device %04x", deviceType);
return BAD_VALUE;
}
} else { // Disconnect
// check if one opened output is not needed any more after disconnecting one device
for (size_t i = 0; i < mOutputs.size(); i++) {
desc = mOutputs.valueAt(i);
if (!desc->isDuplicated()) {
// exact match on device
if (device_distinguishes_on_address(deviceType) && desc->supportsDevice(device)
&& desc->deviceSupportsEncodedFormats(deviceType)) {
outputs.add(mOutputs.keyAt(i));
} else if (!mAvailableOutputDevices.containsAtLeastOne(desc->supportedDevices())) {
ALOGV("checkOutputsForDevice(): disconnecting adding output %d",
mOutputs.keyAt(i));
outputs.add(mOutputs.keyAt(i));
}
}
}
// Clear any profiles associated with the disconnected device.
for (const auto& hwModule : mHwModules) {
for (size_t j = 0; j < hwModule->getOutputProfiles().size(); j++) {
sp<IOProfile> profile = hwModule->getOutputProfiles()[j];
if (profile->supportsDevice(device)) {
ALOGV("checkOutputsForDevice(): "
"clearing direct output profile %zu on module %s",
j, hwModule->getName());
profile->clearAudioProfiles();
}
}
}
}
return NO_ERROR;
}
在该方法中检测device是否有对应的outputs。desc->open打开新的output并创建播放线程playbackthread。
void AudioPolicyManager::checkForDeviceAndOutputChanges(std::function<bool()> onOutputsChecked)
{
// checkA2dpSuspend must run before checkOutputForAllStrategies so that A2DP
// output is suspended before any tracks are moved to it
checkA2dpSuspend();
checkOutputForAllStrategies();
checkSecondaryOutputs();
if (onOutputsChecked != nullptr && onOutputsChecked()) checkA2dpSuspend();
updateDevicesAndOutputs();
if (mHwModules.getModuleFromName(AUDIO_HARDWARE_MODULE_ID_MSD) != 0) {
setMsdPatch();
}
}
再看checkForDeviceAndOutputChanges方法,在该方法中调用了checkOutputForAllStrategies方法。
void AudioPolicyManager::checkOutputForAllStrategies()
{
for (const auto &strategy : mEngine->getOrderedProductStrategies()) {
auto attributes = mEngine->getAllAttributesForProductStrategy(strategy).front();
checkOutputForAttributes(attributes);
}
}
变量所有的strategies并调用checkOutputForAttributes方法。
void AudioPolicyManager::checkOutputForAttributes(const audio_attributes_t &attr)
{
auto psId = mEngine->getProductStrategyForAttributes(attr);
// 根据attr属性找它的旧设备
DeviceVector oldDevices = mEngine->getOutputDevicesForAttributes(attr, 0, true /*fromCache*/);
// 根据attr属性找它的新设备
DeviceVector newDevices = mEngine->getOutputDevicesForAttributes(attr, 0, false /*fromCache*/);
SortedVector<audio_io_handle_t> srcOutputs = getOutputsForDevices(oldDevices, mPreviousOutputs);
SortedVector<audio_io_handle_t> dstOutputs = getOutputsForDevices(newDevices, mOutputs);
// also take into account external policy-related changes: add all outputs which are
// associated with policies in the "before" and "after" output vectors
ALOGVV("%s(): policy related outputs", __func__);
for (size_t i = 0 ; i < mPreviousOutputs.size() ; i++) {
const sp<SwAudioOutputDescriptor> desc = mPreviousOutputs.valueAt(i);
if (desc != 0 && desc->mPolicyMix != NULL) {
srcOutputs.add(desc->mIoHandle);
ALOGVV(" previous outputs: adding %d", desc->mIoHandle);
}
}
for (size_t i = 0 ; i < mOutputs.size() ; i++) {
const sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
if (desc != 0 && desc->mPolicyMix != NULL) {
dstOutputs.add(desc->mIoHandle);
ALOGVV(" new outputs: adding %d", desc->mIoHandle);
}
}
// 如果srcOutputs和dstOutputs不相等,则需要迁移
if (srcOutputs != dstOutputs) {
// get maximum latency of all source outputs to determine the minimum mute time guaranteeing
// audio from invalidated tracks will be rendered when unmuting
uint32_t maxLatency = 0;
for (audio_io_handle_t srcOut : srcOutputs) {
sp<SwAudioOutputDescriptor> desc = mPreviousOutputs.valueFor(srcOut);
if (desc != 0 && maxLatency < desc->latency()) {
maxLatency = desc->latency();
}
}
ALOGV_IF(!(srcOutputs.isEmpty() || dstOutputs.isEmpty()),
"%s: strategy %d, moving from output %s to output %s", __func__, psId,
std::to_string(srcOutputs[0]).c_str(),
std::to_string(dstOutputs[0]).c_str());
// mute strategy while moving tracks from one output to another
for (audio_io_handle_t srcOut : srcOutputs) {
sp<SwAudioOutputDescriptor> desc = mPreviousOutputs.valueFor(srcOut);
if (desc != 0 && desc->isStrategyActive(psId)) {
setStrategyMute(psId, true, desc);
setStrategyMute(psId, false, desc, maxLatency * LATENCY_MUTE_FACTOR,
newDevices.types());
}
sp<SourceClientDescriptor> source = getSourceForAttributesOnOutput(srcOut, attr);
if (source != 0){
connectAudioSource(source);
}
}
// Move effects associated to this stream from previous output to new output
// 将与此流相关的效果从以前的输出移动到新的输出
if (followsSameRouting(attr, attributes_initializer(AUDIO_USAGE_MEDIA))) {
selectOutputForMusicEffects();
}
// Move tracks associated to this stream (and linked) from previous output to new output
将与此流关联的(和链接的)Track从以前的输出移动到新的输出
for (auto stream : mEngine->getStreamTypesForProductStrategy(psId)) {
mpClientInterface->invalidateStream(stream);
}
}
}
checkOutputsForDevice函数遍历支持这种设备的output是否打开,没打开则打开,最后更新当前可用的Outputs和devices。之后调用AudioPolicyManager::checkOutputForAttributes,这个函数会对所有的属性重新寻找该属性的最优设备,由于上一步更新了可用的device,就会找到最优的device为耳机,之后再找到这个设备对应的Output,并和旧的Output对比,如果不一样就会设置这个策略的流为无效,应用层向无效的流写数据就会重新创建track
3. 数据的写入
xref: /frameworks/av/media/libaudioclient/AudioTrack.cpp
status_t AudioTrack::restoreTrack_l(const char *from)
{
..............................................................................................
// If a new IAudioTrack is successfully created, createTrack_l() will modify the
// following member variables: mAudioTrack, mCblkMemory and mCblk.
// It will also delete the strong references on previous IAudioTrack and IMemory.
// If a new IAudioTrack cannot be created, the previous (dead) instance will be left intact.
status_t result = createTrack_l();
..............................................................................................
return result;
}
创建AudioTrack
status_t AudioTrack::createTrack_l()
{
status_t status;
bool callbackAdded = false;
const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger();
if (audioFlinger == 0) {
ALOGE("%s(%d): Could not get audioflinger",
__func__, mPortId);
status = NO_INIT;
goto exit;
}
{
// mFlags (not mOrigFlags) is modified depending on whether fast request is accepted.
// After fast request is denied, we will request again if IAudioTrack is re-created.
// Client can only express a preference for FAST. Server will perform additional tests.
if (mFlags & AUDIO_OUTPUT_FLAG_FAST) {
// either of these use cases:
// use case 1: shared buffer
bool sharedBuffer = mSharedBuffer != 0;
bool transferAllowed =
// use case 2: callback transfer mode
(mTransfer == TRANSFER_CALLBACK) ||
// use case 3: obtain/release mode
(mTransfer == TRANSFER_OBTAIN) ||
// use case 4: synchronous write
((mTransfer == TRANSFER_SYNC || mTransfer == TRANSFER_SYNC_NOTIF_CALLBACK)
&& mThreadCanCallJava);
bool fastAllowed = sharedBuffer || transferAllowed;
if (!fastAllowed) {
ALOGW("%s(%d): AUDIO_OUTPUT_FLAG_FAST denied by client,"
" not shared buffer and transfer = %s",
__func__, mPortId,
convertTransferToText(mTransfer));
mFlags = (audio_output_flags_t) (mFlags & ~AUDIO_OUTPUT_FLAG_FAST);
}
}
IAudioFlinger::CreateTrackInput input;
if (mStreamType != AUDIO_STREAM_DEFAULT) {
input.attr = AudioSystem::streamTypeToAttributes(mStreamType);
} else {
input.attr = mAttributes;
}
input.config = AUDIO_CONFIG_INITIALIZER;
input.config.sample_rate = mSampleRate;
input.config.channel_mask = mChannelMask;
input.config.format = mFormat;
input.config.offload_info = mOffloadInfoCopy;
input.clientInfo.clientUid = mClientUid;
input.clientInfo.clientPid = mClientPid;
input.clientInfo.clientTid = -1;
if (mFlags & AUDIO_OUTPUT_FLAG_FAST) {
// It is currently meaningless to request SCHED_FIFO for a Java thread. Even if the
// application-level code follows all non-blocking design rules, the language runtime
// doesn't also follow those rules, so the thread will not benefit overall.
if (mAudioTrackThread != 0 && !mThreadCanCallJava) {
input.clientInfo.clientTid = mAudioTrackThread->getTid();
}
}
input.sharedBuffer = mSharedBuffer;
input.notificationsPerBuffer = mNotificationsPerBufferReq;
input.speed = 1.0;
if (audio_has_proportional_frames(mFormat) && mSharedBuffer == 0 &&
(mFlags & AUDIO_OUTPUT_FLAG_FAST) == 0) {
input.speed = !isPurePcmData_l() || isOffloadedOrDirect_l() ? 1.0f :
max(mMaxRequiredSpeed, mPlaybackRate.mSpeed);
}
input.flags = mFlags;
input.frameCount = mReqFrameCount;
input.notificationFrameCount = mNotificationFramesReq;
input.selectedDeviceId = mSelectedDeviceId;
input.sessionId = mSessionId;
IAudioFlinger::CreateTrackOutput output;
sp<IAudioTrack> track = audioFlinger->createTrack(input,
output,
&status);
if (status != NO_ERROR || output.outputId == AUDIO_IO_HANDLE_NONE) {
ALOGE("%s(%d): AudioFlinger could not create track, status: %d output %d",
__func__, mPortId, status, output.outputId);
if (status == NO_ERROR) {
status = NO_INIT;
}
goto exit;
}
ALOG_ASSERT(track != 0);
mFrameCount = output.frameCount;
mNotificationFramesAct = (uint32_t)output.notificationFrameCount;
mRoutedDeviceId = output.selectedDeviceId;
mSessionId = output.sessionId;
mSampleRate = output.sampleRate;
if (mOriginalSampleRate == 0) {
mOriginalSampleRate = mSampleRate;
}
mAfFrameCount = output.afFrameCount;
mAfSampleRate = output.afSampleRate;
mAfLatency = output.afLatencyMs;
mLatency = mAfLatency + (1000LL * mFrameCount) / mSampleRate;
// AudioFlinger now owns the reference to the I/O handle,
// so we are no longer responsible for releasing it.
// FIXME compare to AudioRecord
sp<IMemory> iMem = track->getCblk();
if (iMem == 0) {
ALOGE("%s(%d): Could not get control block", __func__, mPortId);
status = NO_INIT;
goto exit;
}
void *iMemPointer = iMem->pointer();
if (iMemPointer == NULL) {
ALOGE("%s(%d): Could not get control block pointer", __func__, mPortId);
status = NO_INIT;
goto exit;
}
// invariant that mAudioTrack != 0 is true only after set() returns successfully
if (mAudioTrack != 0) {
IInterface::asBinder(mAudioTrack)->unlinkToDeath(mDeathNotifier, this);
mDeathNotifier.clear();
}
mAudioTrack = track;
mCblkMemory = iMem;
IPCThreadState::self()->flushCommands();
audio_track_cblk_t* cblk = static_cast<audio_track_cblk_t*>(iMemPointer);
mCblk = cblk;
mAwaitBoost = false;
if (mFlags & AUDIO_OUTPUT_FLAG_FAST) {
if (output.flags & AUDIO_OUTPUT_FLAG_FAST) {
ALOGI("%s(%d): AUDIO_OUTPUT_FLAG_FAST successful; frameCount %zu -> %zu",
__func__, mPortId, mReqFrameCount, mFrameCount);
if (!mThreadCanCallJava) {
mAwaitBoost = true;
}
} else {
ALOGW("%s(%d): AUDIO_OUTPUT_FLAG_FAST denied by server; frameCount %zu -> %zu",
__func__, mPortId, mReqFrameCount, mFrameCount);
}
}
mFlags = output.flags;
//mOutput != output includes the case where mOutput == AUDIO_IO_HANDLE_NONE for first creation
if (mDeviceCallback != 0) {
if (mOutput != AUDIO_IO_HANDLE_NONE) {
AudioSystem::removeAudioDeviceCallback(this, mOutput, mPortId);
}
AudioSystem::addAudioDeviceCallback(this, output.outputId, output.portId);
callbackAdded = true;
}
mPortId = output.portId;
// We retain a copy of the I/O handle, but don't own the reference
mOutput = output.outputId;
mRefreshRemaining = true;
// Starting address of buffers in shared memory. If there is a shared buffer, buffers
// is the value of pointer() for the shared buffer, otherwise buffers points
// immediately after the control block. This address is for the mapping within client
// address space. AudioFlinger::TrackBase::mBuffer is for the server address space.
void* buffers;
if (mSharedBuffer == 0) {
buffers = cblk + 1;
} else {
buffers = mSharedBuffer->pointer();
if (buffers == NULL) {
ALOGE("%s(%d): Could not get buffer pointer", __func__, mPortId);
status = NO_INIT;
goto exit;
}
}
mAudioTrack->attachAuxEffect(mAuxEffectId);
// If IAudioTrack is re-created, don't let the requested frameCount
// decrease. This can confuse clients that cache frameCount().
if (mFrameCount > mReqFrameCount) {
mReqFrameCount = mFrameCount;
}
// reset server position to 0 as we have new cblk.
mServer = 0;
// update proxy
if (mSharedBuffer == 0) {
mStaticProxy.clear();
mProxy = new AudioTrackClientProxy(cblk, buffers, mFrameCount, mFrameSize);
} else {
mStaticProxy = new StaticAudioTrackClientProxy(cblk, buffers, mFrameCount, mFrameSize);
mProxy = mStaticProxy;
}
mProxy->setVolumeLR(gain_minifloat_pack(
gain_from_float(mVolume[AUDIO_INTERLEAVE_LEFT]),
gain_from_float(mVolume[AUDIO_INTERLEAVE_RIGHT])));
mProxy->setSendLevel(mSendLevel);
const uint32_t effectiveSampleRate = adjustSampleRate(mSampleRate, mPlaybackRate.mPitch);
const float effectiveSpeed = adjustSpeed(mPlaybackRate.mSpeed, mPlaybackRate.mPitch);
const float effectivePitch = adjustPitch(mPlaybackRate.mPitch);
mProxy->setSampleRate(effectiveSampleRate);
AudioPlaybackRate playbackRateTemp = mPlaybackRate;
playbackRateTemp.mSpeed = effectiveSpeed;
playbackRateTemp.mPitch = effectivePitch;
mProxy->setPlaybackRate(playbackRateTemp);
mProxy->setMinimum(mNotificationFramesAct);
mDeathNotifier = new DeathNotifier(this);
IInterface::asBinder(mAudioTrack)->linkToDeath(mDeathNotifier, this);
}
exit:
if (status != NO_ERROR && callbackAdded) {
// note: mOutput is always valid is callbackAdded is true
AudioSystem::removeAudioDeviceCallback(this, mOutput, mPortId);
}
mStatus = status;
// sp<IAudioTrack> track destructor will cause releaseOutput() to be called by AudioFlinger
return status;
}
最终会通过audioFlinger->createTrack在audioFlinger中创建一个新的track跟audioTrack相对应。后面数据会传给新的track,从而在新的设备上播放出来。