Android 音频源码分析——音频设备切换(插入耳机)
Posted zpy_公众号_码农修仙儿
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, address, outputs);
}
}
}
// 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->supportDevice(device)) {
if (!device_distinguishes_on_address(device) ||
profile->supportDeviceAddress(address)) {
profiles.add(profile);
}
}
}
}
if (profiles.isEmpty() && outputs.isEmpty()) {
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++) {
//......
desc = new SwAudioOutputDescriptor(profile, mpClientInterface);
audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
status_t status = desc->open(nullptr, device, address,
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(device, address);
mpClientInterface->setParameters(output, String8(param));
free(param);
}
//....
}
if (profiles.isEmpty()) {
return BAD_VALUE;
}
} else { // Disconnect
// .....
}
return NO_ERROR;
}
- 查找output是否支持该device,现在是扬声器对应primary,不支持usb device;
- 查找该设备支持的output profile;
- 根据profile创建SwAudioOutputDescriptor,并调用open函数,打开open output stream,创建PalybackThread子类(这里对于usb耳机,应该是OffloadThread);
- 更新output的参数;
这里分析下desc->open流程
status_t SwAudioOutputDescriptor::open(const audio_config_t *config,
audio_devices_t device,
const String8& address,
audio_stream_type_t stream,
audio_output_flags_t flags,
audio_io_handle_t *output)
{
//......
status_t status = mClientInterface->openOutput(mProfile->getModuleHandle(),
output,
&lConfig,
&mDevice,
address,
&mLatency,
mFlags);
}
status_t AudioPolicyService::AudioPolicyClient::openOutput(audio_module_handle_t module,
audio_io_handle_t *output,
audio_config_t *config,
audio_devices_t *devices,
const String8& address,
uint32_t *latencyMs,
audio_output_flags_t flags)
{
sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
if (af == 0) {
return PERMISSION_DENIED;
}
return af->openOutput(module, output, config, devices, address, latencyMs, flags);
}
流程如下
SwAudioOutputDescriptor::open
——》AudioPolicyClient::openOutput
——》AudioFlinger::openOutput
——》AudioFlinger::openOutput_l
AudioFlinger openOutput_l函数
sp<AudioFlinger::ThreadBase> AudioFlinger::openOutput_l(audio_module_handle_t module,
audio_io_handle_t *output,
audio_config_t *config,
audio_devices_t devices,
const String8& address,
audio_output_flags_t flags)
{
AudioHwDevice *outHwDev = findSuitableHwDev_l(module, devices);
if (outHwDev == NULL) {
return 0;
}
if (*output == AUDIO_IO_HANDLE_NONE) {
*output = nextUniqueId(AUDIO_UNIQUE_ID_USE_OUTPUT);
} else {
return 0;
}
mHardwareStatus = AUDIO_HW_OUTPUT_OPEN;
AudioStreamOut *outputStream = NULL;
status_t status = outHwDev->openOutputStream(
&outputStream,
*output,
devices,
flags,
config,
address.string());
mHardwareStatus = AUDIO_HW_IDLE;
if (status == NO_ERROR) {
if (flags & AUDIO_OUTPUT_FLAG_MMAP_NOIRQ) {
sp<MmapPlaybackThread> thread =
new MmapPlaybackThread(this, *output, outHwDev, outputStream,
devices, AUDIO_DEVICE_NONE, mSystemReady);
mMmapThreads.add(*output, thread);
return thread;
} else {
sp<PlaybackThread> thread;
if (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
thread = new OffloadThread(this, outputStream, *output, devices, mSystemReady);
} else if ((flags & AUDIO_OUTPUT_FLAG_DIRECT)
|| !isValidPcmSinkFormat(config->format)
|| !isValidPcmSinkChannelMask(config->channel_mask)) {
} else {
thread = new MixerThread(this, outputStream, *output, devices, mSystemReady);
}
mPlaybackThreads.add(*output, thread);
return thread;
}
}
return 0;
}
- findSuitableHwDev_l 查找AudioHwDevice;
- outHwDev->openOutputStream 打开output stream;
- 根据flags创建thread,这里usb 耳机对应创建OffloadThread;
2 checkOutputForAllStrategies
checkOutputForAllStrategies针对所有strategy,调用checkOutputForStrategy函数处理。
void AudioPolicyManager::checkOutputForAllStrategies()
{
if (mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) == AUDIO_POLICY_FORCE_SYSTEM_ENFORCED)
checkOutputForStrategy(STRATEGY_ENFORCED_AUDIBLE);
checkOutputForStrategy(STRATEGY_PHONE);
if (mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) != AUDIO_POLICY_FORCE_SYSTEM_ENFORCED)
checkOutputForStrategy(STRATEGY_ENFORCED_AUDIBLE);
checkOutputForStrategy(STRATEGY_SONIFICATION);
checkOutputForStrategy(STRATEGY_SONIFICATION_RESPECTFUL);
checkOutputForStrategy(STRATEGY_ACCESSIBILITY);
checkOutputForStrategy(STRATEGY_MEDIA);
checkOutputForStrategy(STRATEGY_DTMF);
checkOutputForStrategy(STRATEGY_REROUTING);
}
void AudioPolicyManager::checkOutputForStrategy(routing_strategy strategy)
{
audio_devices_t oldDevice = getDeviceForStrategy(strategy, true /*fromCache*/);
audio_devices_t newDevice = getDeviceForStrategy(strategy, false /*fromCache*/);
SortedVector<audio_io_handle_t> srcOutputs = getOutputsForDevice(oldDevice, mPreviousOutputs);
SortedVector<audio_io_handle_t> dstOutputs = getOutputsForDevice(newDevice, mOutputs);
// also take into account external policy-related changes: add all outputs which are
// associated with policies in the "before" and "after" output vectors
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);
}
}
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);
}
}
if (!vectorsEqual(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();
}
}
// 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 && isStrategyActive(desc, strategy)) {
setStrategyMute(strategy, true, desc);
setStrategyMute(strategy, false, desc, maxLatency * LATENCY_MUTE_FACTOR, newDevice);
}
sp<AudioSourceDescriptor> source =
getSourceForStrategyOnOutput(srcOut, strategy);
if (source != 0){
connectAudioSource(source);
}
}
// Move effects associated to this strategy from previous output to new output
if (strategy == STRATEGY_MEDIA) {
selectOutputForMusicEffects();
}
// Move tracks associated to this strategy from previous output to new output
for (int i = 0; i < AUDIO_STREAM_FOR_POLICY_CNT; i++) {
if (getStrategy((audio_stream_type_t)i) == strategy) {
mpClientInterface->invalidateStream((audio_stream_type_t)i);
}
}
}
}
checkOutputForStrategy对比先后的ouputs,如果不同进行下述处理
- setStrategyMute 静音一定时间;
- invalidateStream 将与当前策略有关的stream 从先前output移除,针对当前stream的Track设置为CBLK_INVALID,后续重新创建Track;
分析下 invalidateStream
status_t AudioFlinger::invalidateStream(audio_stream_type_t stream)
{
Mutex::Autolock _l(mLock);
for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
PlaybackThread *thread = mPlaybackThreads.valueAt(i).get();
thread->invalidateTracks(stream);
}
for (size_t i = 0; i < mMmapThreads.size(); i++) {
mMmapThreads[i]->invalidateTracks(stream);
}
return NO_ERROR;
}
bool AudioFlinger::PlaybackThread::invalidateTracks_l(audio_stream_type_t streamType)
{
bool trackMatch = false;
size_t size = mTracks.size();
for (size_t i = 0; i < size; i++) {
sp<Track> t = mTracks[i];
if (t->streamType() == streamType && t->isExternalTrack()) {
t->invalidate();
trackMatch = true;
}
}
return trackMatch;
}
获取该stream对应的 PlaybackThread,将其包含的track 置为无效 CBLK_INVALID,扬声器对应track 则不能在进行播放了。后续根据新设备创建新的Track,进行播放。
3 closeOutput
对于设备断开连接或checkOutputsForDeivce中打开的direct outputs,则需要进行关闭。usb 耳机回打开 direct outputs,所以这里需要关闭outputs
这里分析下closeOutput流程
void AudioPolicyManager::closeOutput(audio_io_handle_t output)
{
sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueFor(output);
mPolicyMixes.closeOutput(outputDesc);
// look for duplicated outputs connected to the output being removed.
//..........
outputDesc->close();
removeOutput(output);
mPreviousOutputs = mOutputs;
}
直接看 AudioFlinger
status_t AudioFlinger::closeOutput(audio_io_handle_t output)
{
return closeOutput_nonvirtual(output);
}
status_t AudioFlinger::closeOutput_nonvirtual(audio_io_handle_t output)
{
// keep strong reference on the playback thread so that
// it is not destroyed while exit() is executed
sp<PlaybackThread> playbackThread;
sp<MmapPlaybackThread> mmapThread;
{
Mutex::Autolock _l(mLock);
playbackThread = checkPlaybackThread_l(output);
if (playbackThread != NULL) {
if (playbackThread->type() == ThreadBase::MIXER) {
for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
if (mPlaybackThreads.valueAt(i)->isDuplicating()) {
DuplicatingThread *dupThread =
(DuplicatingThread *)mPlaybackThreads.valueAt(i).get();
dupThread->removeOutputTrack((MixerThread *)playbackThread.get());
}
}
}
mPlaybackThreads.removeItem(output);
// save all effects to the default thread
if (mPlaybackThreads.size()) {
PlaybackThread *dstThread = checkPlaybackThread_l(mPlaybackThreads.keyAt(0));
if (dstThread != NULL) {
// audioflinger lock is held so order of thread lock acquisition doesn't matter
Mutex::Autolock _dl(dstThread->mLock);
Mutex::Autolock _sl(playbackThread->mLock);
Vector< sp<EffectChain> > effectChains = playbackThread->getEffectChains_l();
for (size_t i = 0; i < effectChains.size(); i ++) {
moveEffectChain_l(effectChains[i]->sessionId(), playbackThread.get(),
dstThread, true);
}
}
}
} else {
mmapThread = (MmapPlaybackThread *)checkMmapThread_l(output);
if (mmapThread == 0) {
return BAD_VALUE;
}
mMmapThreads.removeItem(output);
ALOGD("closing mmapThread %p", mmapThread.get());
}
const sp<AudioIoDescriptor> ioDesc = new AudioIoDescriptor();
ioDesc->mIoHandle = output;
ioConfigChanged(AUDIO_OUTPUT_CLOSED, ioDesc);
}
// The thread entity (active unit of execution) is no longer running here,
// but the ThreadBase container still exists.
if (playbackThread != 0) {
playbackThread->exit();
if (!playbackThread->isDuplicating()) {
closeOutputFinish(playbackThread);
}
} else if (mmapThread != 0) {
ALOGD("mmapThread exit()");
mmapThread->exit();
AudioStreamOut *out = mmapThread->clearOutput();
ALOG_ASSERT(out != NULL, "out shouldn't be NULL");
// from now on thread->mOutput is NULL
delete out;
}
return NO_ERROR;
}
- PlaybackThread 删除 output;
- PlaybackThread 退出线程;
三、AudioTrack
AudioTrack 包含多个函数 如:start() processAudioBuffer getTimestamp_l getPosition等,都会检查flags 是否包含CBLK_INVALID状态,如果是此状态则调用restoreTrack_l重新创建Track,这样完成设备的切换,使用usb 耳机播放声音。
该流程暂不分析。
以上是关于Android 音频源码分析——音频设备切换(插入耳机)的主要内容,如果未能解决你的问题,请参考以下文章
Android 音频源码分析——AudioTrack设备选择