Android 音频源码分析——音频设备切换(插入耳机)
Posted VNanyesheshou
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 音频源码分析——音频设备切换(插入耳机)相关的知识,希望对你有一定的参考价值。
源码分析基于android9.0
通常带线耳机分类
- 模拟耳机
平时常用的3.5mm或6.3mm接口耳机,接收模拟信号(音频数据需要先处理,转码成pcm格式)
android中模拟耳机由WiredAccessoryManager获取上报的事件,调用AudioService.setWiredDeviceConnectionState传递信息给Audioservice,更新设备信息。 - 数字耳机
例如USB Type-c耳机,接收数字信号(音频数据不需要解码成pcm,由耳机进行转换)
Android中由UsbAlsaManager负责usb音频设备连接断开事件,调用AudioService.setWiredDeviceConnectionState传递信息给AudioService。
使用扬声器播放音乐,此时插入耳机,则音乐切换从耳机播放出。这里以插入数字耳机为例分析下音频设备切换流程。
一、Framework层
当设备插入usb 耳机,UsbHostManager会接收到usb设备事件调用usbDeviceAdded函数,调到UsbAlsaManager.usbDeviceAdded函数。
UsbAlsaManager.java
void usbDeviceAdded(String deviceAddress, UsbDevice usbDevice,
UsbDescriptorParser parser)
//...
if (hasInput || hasOutput)
UsbAlsaDevice alsaDevice =
new UsbAlsaDevice(mAudioService, cardRec.getCardNum(), 0 /*device*/,
deviceAddress, hasOutput, hasInput,
isInputHeadset, isOutputHeadset);
if (alsaDevice != null)
alsaDevice.setDeviceNameAndDescription(
cardRec.getCardName(), cardRec.getCardDescription());
mAlsaDevices.add(0, alsaDevice);
selectAlsaDevice(alsaDevice);
private synchronized void selectAlsaDevice(UsbAlsaDevice alsaDevice)
//.......
mSelectedDevice = alsaDevice;
alsaDevice.start();
- 创建UsbAlsaDevice,并设置信息;
- 设置为mSelectedDevice;
- 调用UsbAlsaDevice start,更新设备连接状态;
接着看UsbAlsaDevice start
public synchronized void start()
mSelected = true;
mInputState = 0;
mOutputState = 0;
startJackDetect();
updateWiredDeviceConnectionState(true);
public synchronized void updateWiredDeviceConnectionState(boolean enable)
//.......
if (mHasOutput)
mAudioService.setWiredDeviceConnectionState(device, outputState,
alsaCardDeviceString,
mDeviceName, TAG);
if (mHasInput)
mAudioService.setWiredDeviceConnectionState(
device, inputState, alsaCardDeviceString,
mDeviceName, TAG);
调用AudioService,设置设备连接状态。
AudioService
接下来分析AudioService中流程
public void setWiredDeviceConnectionState(int type, int state, String address, String name,
String caller)
synchronized (mConnectedDevices)
if (DEBUG_DEVICES)
Slog.i(TAG, "setWiredDeviceConnectionState(" + state + " nm: " + name + " addr:"
+ address + ")");
int delay = checkSendBecomingNoisyIntent(type, state, AudioSystem.DEVICE_NONE);
queueMsgUnderWakeLock(mAudioHandler,
MSG_SET_WIRED_DEVICE_CONNECTION_STATE,
0 /* arg1 unused */,
0 /* arg2 unused */,
new WiredDeviceConnectionState(type, state, address, name, caller),
delay);
发送Message消息,由AudioHandler处理
public void handleMessage(Message msg)
switch (msg.what)
case MSG_SET_WIRED_DEVICE_CONNECTION_STATE:
WiredDeviceConnectionState connectState =
(WiredDeviceConnectionState)msg.obj;
mDeviceLogger.log(new WiredDevConnectEvent(connectState));
onSetWiredDeviceConnectionState(connectState.mType, connectState.mState,
connectState.mAddress, connectState.mName, connectState.mCaller);
mAudioEventWakeLock.release();
break;
接着看onSetWiredDeviceConnectionState函数
private void onSetWiredDeviceConnectionState(int device, int state, String address,
String deviceName, String caller)
synchronized (mConnectedDevices)
if ((state == 0) && ((device & DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG) != 0))
setBluetoothA2dpOnInt(true, "onSetWiredDeviceConnectionState state 0");
if (!handleDeviceConnection(state == 1, device, address, deviceName))
// change of connection state failed, bailout
return;
//.....
sendDeviceConnectionIntent(device, state, address, deviceName);
updateAudioRoutes(device, state);
- 如果是设备拔出,则设置A2dp;
- handleDeviceConnection 处理设备连接;
- 发送广播、更新audio通路;
接着分析handleDeviceConnection
private boolean handleDeviceConnection(boolean connect, int device, String address,
String deviceName)
synchronized (mConnectedDevices)
String deviceKey = makeDeviceListKey(device, address);
DeviceListSpec deviceSpec = mConnectedDevices.get(deviceKey);
boolean isConnected = deviceSpec != null;
if (connect && !isConnected)
//连接 处理
final int res = AudioSystem.setDeviceConnectionState(device,
AudioSystem.DEVICE_STATE_AVAILABLE, address, deviceName);
if (res != AudioSystem.AUDIO_STATUS_OK)
return false;
mConnectedDevices.put(deviceKey, new DeviceListSpec(device, deviceName, address));
sendMsg(mAudioHandler, MSG_ACCESSORY_PLUG_MEDIA_UNMUTE, SENDMSG_QUEUE,
device, 0, null, 0);
return true;
else if (!connect && isConnected)
//断开连接 处理
AudioSystem.setDeviceConnectionState(device,
AudioSystem.DEVICE_STATE_UNAVAILABLE, address, deviceName);
// always remove even if disconnection failed
mConnectedDevices.remove(deviceKey);
return true;
return false;
调用AudioSystem.setDeviceConnectionState处理状态,连接或者断开连接都调用此流程,只是参数不同,连接对应DEVICE_STATE_AVAILABLE。
接着看AudioSystem
AudioSystem
AudioSystem.java
public static native int setDeviceConnectionState(int device, int state,
String device_address, String device_name);
setDeviceConnectionState为native方法,直接看jni对应实现
android_media_AudioSystem.cpp
static jint
android_media_AudioSystem_setDeviceConnectionState(JNIEnv *env, jobject thiz, jint device, jint state, jstring device_address, jstring device_name)
const char *c_address = env->GetStringUTFChars(device_address, NULL);
const char *c_name = env->GetStringUTFChars(device_name, NULL);
int status = check_AudioSystem_Command(AudioSystem::setDeviceConnectionState(static_cast <audio_devices_t>(device),
static_cast <audio_policy_dev_state_t>(state),
c_address, c_name));
env->ReleaseStringUTFChars(device_address, c_address);
env->ReleaseStringUTFChars(device_name, c_name);
return (jint) status;
这里继续向下追查
AudioSystem.cpp
status_t AudioSystem::setDeviceConnectionState(audio_devices_t device,
audio_policy_dev_state_t state,
const char *device_address,
const char *device_name)
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);
- 获取AudioPolicyService;
- 快进程调用AudioPolicyService setDeviceConnectionState;
二、audioserver
status_t AudioPolicyService::setDeviceConnectionState(audio_devices_t device,
audio_policy_dev_state_t state,
const char *device_address,
const char *device_name)
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);
- 检查mAudioPolicyManager、权限、state;
- 调用AudioPolicyManager对应setDeviceConnectionState;
AudioPolicyManager
setDeviceConnectionState调用setDeviceConnectionStateInt。
status_t AudioPolicyManager::setDeviceConnectionState(audio_devices_t device,
audio_policy_dev_state_t state,
const char *device_address,
const char *device_name)
status_t status = setDeviceConnectionStateInt(device, state, device_address, device_name);
nextAudioPortGeneration();
return status;
status_t AudioPolicyManager::setDeviceConnectionStateInt(audio_devices_t device,
audio_policy_dev_state_t state,
const char *device_address,
const char *device_name)
// connect/disconnect only 1 device at a time
if (!audio_is_output_device(device) && !audio_is_input_device(device)) return BAD_VALUE;
sp<DeviceDescriptor> devDesc =
mHwModules.getDeviceDescriptor(device, device_address, device_name);
// 处理输出设备
if (audio_is_output_device(device))
SortedVector <audio_io_handle_t> outputs;
ssize_t index = mAvailableOutputDevices.indexOf(devDesc);
// 在通过checkOutputsForDevice()打开或关闭任何输出之前,请保存打开的输出描述符的副本。 checkOutputForAllStrategies()将需要它
mPreviousOutputs = mOutputs;
switch (state)
// 处理输出设备连接
case AUDIO_POLICY_DEVICE_STATE_AVAILABLE:
if (index >= 0)
return INVALID_OPERATION;
// register new device as available
index = mAvailableOutputDevices.add(devDesc);
if (index >= 0)
sp<HwModule> module = mHwModules.getModuleForDevice(device);
if (module == 0)
mAvailableOutputDevices.remove(devDesc);
return INVALID_OPERATION;
mAvailableOutputDevices[index]->attach(module);
else
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, devDesc->mAddress);
if (checkOutputsForDevice(devDesc, state, outputs, devDesc->mAddress) != NO_ERROR)
mAvailableOutputDevices.remove(devDesc);
broadcastDeviceConnectionState(device, AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
devDesc->mAddress);
return INVALID_OPERATION;
// Propagate device availability to Engine
mEngine->setDeviceConnectionState(devDesc, state);
break;
// 处理输出设备断开连接
case AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE:
//....
break;
default:
return BAD_VALUE;
// checkA2dpSuspend must run before checkOutputForAllStrategies so that A2DP
// output is suspended before any tracks are moved to it
checkA2dpSuspend();
checkOutputForAllStrategies();
// outputs must be closed after checkOutputForAllStrategies() is executed
if (!outputs.isEmpty())
for (audio_io_handle_t output : outputs)
sp<SwAudioOutputDescriptor> desc = mOutputs.valueFor(output);
// close unused outputs after device disconnection or direct outputs that have been
// opened by checkOutputsForDevice() to query dynamic parameters
if ((state == AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE) ||
(((desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) != 0) &&
(desc->mDirectOpenCount == 0)))
closeOutput(output);
// check again after closing A2DP output to reset mA2dpSuspended if needed
checkA2dpSuspend();
updateDevicesAndOutputs();
if (mEngine->getPhoneState() == AUDIO_MODE_IN_CALL && hasPrimaryOutput())
audio_devices_t newDevice = getNewOutputDevice(mPrimaryOutput, false /*fromCache*/);
updateCallRouting(newDevice);
for (size_t i = 0; i < mOutputs.size(); i++)
sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
if ((mEngine->getPhoneState() != AUDIO_MODE_IN_CALL) || (desc != mPrimaryOutput))
audio_devices_t newDevice = getNewOutputDevice(desc, true /*fromCache*/);
// 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.
bool force = !desc->isDuplicated()
&& (!device_distinguishes_on_address(device)
// always force when disconnecting (a non-duplicated device)
|| (state == AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE));
setOutputDevice(desc, newDevice, force, 0);
if (state == AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE)
cleanUpForDevice(devDesc);
mpClientInterface->onAudioPortListUpdate();
return NO_ERROR;
// end if is output device
分析setDeviceConnectionStateInt
- 注册新设备到mAvailableOutputDevices,并绑定其HWModules;
- broadcastDeviceConnectionState 在检查outputs前,广播连接事件以允许hal在新连接的设备上检索动态参数(而不是打开输出);
- checkOutputsForDevice 检查设备支持profile,并打开output,更新output参数;
- checkA2dpSuspend 检查a2dp;
- checkOutputForAllStrategies检查所有音频 strategy,并将不一致outputs,对应track置为无效;
- closeOutput 设备断开连接或checkOutputsForDeivce中打开的direct outputs,则进行关闭。
- updateDevicesAndOutputs 更新devices 和outputs;
- setOutputDevice 设置输出设备;
1 checkOutputsForDevice
检查device的outputs。
status_t AudioPolicyManager::checkOutputsForDevice(const sp<DeviceDescriptor>& devDesc,
audio_policy_dev_state_t state,
SortedVector<audio_io_handle_t>& outputs,
const String8& address)
//.........
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->supportedDevices() & device))
if (!device_distinguishes_on_address(device))
outputs.add(mOutputs.keyAt(i));
else
findIoHandlesByAddress(desc, device, addressAndroid 音频源码分析——音频设备切换(插入耳机)
Android 音频源码分析——AudioTrack设备选择