Android 音频源码分析——AudioTrack设备选择
Posted VNanyesheshou
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 音频源码分析——AudioTrack设备选择相关的知识,希望对你有一定的参考价值。
Android 音频源码分析——AndroidRecord录音(一)
Android 音频源码分析——AndroidRecord录音(二)
Android 音频源码分析——AndroidRecord音频数据传输流程
Android 音频源码分析——audioserver启动
Android 音频源码分析——AudioFlinger
Android 音频源码分析——AudioTrack设备选择
基于Andorid9.0源码
以AudioTrack为例,梳理下输出设备选择流程。
音频设备选择的影响因素:
- AudioAttributes 声音流类型
- setForceUse 设置
- setPreferredDevice设置 (AudioRecord、AudioTrack、MediaRecorder、MediaPlayer)
- 等。。。。待研究
一、大多数情况输出设备选择
直接从AudioTrack.cpp 开始。
AudioTrack构造器
》AudioTrack::set()
》AudioTrack::createTrack_l()
》audioFlinger->createTrack(input, output, &status);
》AudioFlinger::createTrack()
》Audiosystem::getOutputForAttr()
》AudioPolicyService::getOutputForAttr()
》AudioPolicyManager::getOutputForAttr()
status_t AudioPolicyManager::getOutputForAttr(const audio_attributes_t *attr,
audio_io_handle_t *output,
audio_session_t session,
audio_stream_type_t *stream,
uid_t uid,
const audio_config_t *config,
audio_output_flags_t *flags,
audio_port_handle_t *selectedDeviceId,
audio_port_handle_t *portId)
//获取stream type
*stream = streamTypefromAttributesInt(&attributes)
routing_strategy strategy = (routing_strategy) getStrategyForAttr(&attributes)
audio_devices_t device = getDeviceForStrategy(strategy, false /*fromCache*/);
*output = getOutputForDevice(device, session, *stream, config, flags);
- 通过AudioAttribute中的flags和usage获取对应的Stream type;
- AudioAttribute usage属性映射到strategy;
- 通过strategy 选择device类型;
- 选择音频设备、音频通路;
1. 获取stream type
通过flags和usage映射到 stream type
audio_stream_type_t AudioPolicyManager::streamTypefromAttributesInt(const audio_attributes_t *attr)
// flags to stream type mapping
if ((attr->flags & AUDIO_FLAG_AUDIBILITY_ENFORCED) == AUDIO_FLAG_AUDIBILITY_ENFORCED)
return AUDIO_STREAM_ENFORCED_AUDIBLE;
if ((attr->flags & AUDIO_FLAG_SCO) == AUDIO_FLAG_SCO)
return AUDIO_STREAM_BLUETOOTH_SCO;
if ((attr->flags & AUDIO_FLAG_BEACON) == AUDIO_FLAG_BEACON)
return AUDIO_STREAM_TTS;
// usage to stream type mapping
switch (attr->usage)
case AUDIO_USAGE_MEDIA:
case AUDIO_USAGE_GAME:
case AUDIO_USAGE_ASSISTANT:
case AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE:
return AUDIO_STREAM_MUSIC;
case AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY:
return AUDIO_STREAM_ACCESSIBILITY;
case AUDIO_USAGE_ASSISTANCE_SONIFICATION:
return AUDIO_STREAM_SYSTEM;
case AUDIO_USAGE_VOICE_COMMUNICATION:
return AUDIO_STREAM_VOICE_CALL;
case AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING:
return AUDIO_STREAM_DTMF;
case AUDIO_USAGE_ALARM:
return AUDIO_STREAM_ALARM;
case AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE:
return AUDIO_STREAM_RING;
case AUDIO_USAGE_NOTIFICATION:
case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST:
case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT:
case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED:
case AUDIO_USAGE_NOTIFICATION_EVENT:
return AUDIO_STREAM_NOTIFICATION;
case AUDIO_USAGE_UNKNOWN:
default:
return AUDIO_STREAM_MUSIC;
2. 获取strategy
getStrategyForAttr会调到Engine的getStrategyForUsage函数
routing_strategy Engine::getStrategyForUsage(audio_usage_t usage)
// usage to strategy mapping
switch (usage)
case AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY:
return STRATEGY_ACCESSIBILITY;
case AUDIO_USAGE_MEDIA:
case AUDIO_USAGE_GAME:
case AUDIO_USAGE_ASSISTANT:
case AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE:
case AUDIO_USAGE_ASSISTANCE_SONIFICATION:
return STRATEGY_MEDIA;
case AUDIO_USAGE_VOICE_COMMUNICATION:
return STRATEGY_PHONE;
case AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING:
return STRATEGY_DTMF;
case AUDIO_USAGE_ALARM:
case AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE:
return STRATEGY_SONIFICATION;
case AUDIO_USAGE_NOTIFICATION:
case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST:
case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT:
case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED:
case AUDIO_USAGE_NOTIFICATION_EVENT:
return STRATEGY_SONIFICATION_RESPECTFUL;
case AUDIO_USAGE_UNKNOWN:
default:
return STRATEGY_MEDIA;
AudioAttribute usage属性映射到strategy。
3. 获取设备类型
audio_devices_t AudioPolicyManager::getDeviceForStrategy(routing_strategy strategy,
bool fromCache)
// Check if an explicit routing request exists for a stream type corresponding to the
// specified strategy and use it in priority over default routing rules.
for (int stream = 0; stream < AUDIO_STREAM_FOR_POLICY_CNT; stream++)
if (getStrategy((audio_stream_type_t)stream) == strategy)
audio_devices_t forcedDevice =
mOutputRoutes.getActiveDeviceForStream(
(audio_stream_type_t)stream, mAvailableOutputDevices);
if (forcedDevice != AUDIO_DEVICE_NONE)
return forcedDevice;
if (fromCache)
ALOGVV("getDeviceForStrategy() from cache strategy %d, device %x",
strategy, mDeviceForStrategy[strategy]);
return mDeviceForStrategy[strategy];
return mEngine->getDeviceForStrategy(strategy);
- 检查是否存在与指定策略相对应的流类型的显示route请求,并优先于默认规则
- 是否从缓存中获取设备,这里framCache为false
- Engine中获取strategy对应的默认设备类型
Engine有两种:
frameworks/av/services/audioplicy/enginedefault/src/Engine.cpp 对应使用 audio_policy.conf
frameworks/av/services/audioplicy/engineconfigurable/src/Engine.cpp 对应使用 audio_policy_configuration.xml
这里以default为例,接着分析Engine中获取strategy对应的默认设备类型,代码较长,主要分析下STRATEGY_MEDIA 策略。
audio_devices_t Engine::getDeviceForStrategy(routing_strategy strategy) const
DeviceVector availableOutputDevices = mApmObserver->getAvailableOutputDevices();
DeviceVector availableInputDevices = mApmObserver->getAvailableInputDevices();
const SwAudioOutputCollection &outputs = mApmObserver->getOutputs();
return getDeviceForStrategyInt(strategy, availableOutputDevices,
availableInputDevices, outputs, (uint32_t)AUDIO_DEVICE_NONE);
audio_devices_t Engine::getDeviceForStrategyInt(routing_strategy strategy,
DeviceVector availableOutputDevices,
DeviceVector availableInputDevices,
const SwAudioOutputCollection &outputs,
uint32_t outputDeviceTypesToIgnore) const
uint32_t device = AUDIO_DEVICE_NONE;
uint32_t availableOutputDevicesType =
availableOutputDevices.types() & ~outputDeviceTypesToIgnore;
switch (strategy)
//省略。。。。。。
case STRATEGY_MEDIA:
uint32_t device2 = AUDIO_DEVICE_NONE;
if (strategy != STRATEGY_SONIFICATION)
// no sonification on remote submix (e.g. WFD)
if (availableOutputDevices.getDevice(AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
String8("0")) != 0)
device2 = availableOutputDevices.types() & AUDIO_DEVICE_OUT_REMOTE_SUBMIX;
if (isInCall() && (strategy == STRATEGY_MEDIA))
device = getDeviceForStrategyInt(
STRATEGY_PHONE, availableOutputDevices, availableInputDevices, outputs,
outputDeviceTypesToIgnore);
break;
if (device2 == AUDIO_DEVICE_NONE)
device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_HEARING_AID;
if ((device2 == AUDIO_DEVICE_NONE) &&
(mForceUse[AUDIO_POLICY_FORCE_FOR_MEDIA] != AUDIO_POLICY_FORCE_NO_BT_A2DP) &&
outputs.isA2dpSupported())
device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP;
if (device2 == AUDIO_DEVICE_NONE)
device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES;
if (device2 == AUDIO_DEVICE_NONE)
device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER;
if ((device2 == AUDIO_DEVICE_NONE) &&
(mForceUse[AUDIO_POLICY_FORCE_FOR_MEDIA] == AUDIO_POLICY_FORCE_SPEAKER))
device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_SPEAKER;
if (device2 == AUDIO_DEVICE_NONE)
device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_WIRED_HEADPHONE;
if (device2 == AUDIO_DEVICE_NONE)
device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_LINE;
if (device2 == AUDIO_DEVICE_NONE)
device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_WIRED_HEADSET;
if (device2 == AUDIO_DEVICE_NONE)
device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_USB_HEADSET;
if (device2 == AUDIO_DEVICE_NONE)
device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_USB_ACCESSORY;
if (device2 == AUDIO_DEVICE_NONE)
device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_USB_DEVICE;
if (device2 == AUDIO_DEVICE_NONE)
device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET;
if ((device2 == AUDIO_DEVICE_NONE) && (strategy != STRATEGY_SONIFICATION))
// no sonification on aux digital (e.g. HDMI)
device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_AUX_DIGITAL;
if ((device2 == AUDIO_DEVICE_NONE) &&
(mForceUse[AUDIO_POLICY_FORCE_FOR_DOCK] == AUDIO_POLICY_FORCE_ANALOG_DOCK))
device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET;
if (device2 == AUDIO_DEVICE_NONE)
device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_SPEAKER;
int device3 = AUDIO_DEVICE_NONE;
if (strategy == STRATEGY_MEDIA)
// ARC, SPDIF and AUX_LINE can co-exist with others.
device3 = availableOutputDevicesType & AUDIO_DEVICE_OUT_HDMI_ARC;
device3 |= (availableOutputDevicesType & AUDIO_DEVICE_OUT_SPDIF);
device3 |= (availableOutputDevicesType & AUDIO_DEVICE_OUT_AUX_LINE);
device2 |= device3;
// device is DEVICE_OUT_SPEAKER if we come from case STRATEGY_SONIFICATION or
// STRATEGY_ENFORCED_AUDIBLE, AUDIO_DEVICE_NONE otherwise
device |= device2;
// If hdmi system audio mode is on, remove speaker out of output list.
if ((strategy == STRATEGY_MEDIA) &&
(mForceUse[AUDIO_POLICY_FORCE_FOR_HDMI_SYSTEM_AUDIO] ==
AUDIO_POLICY_FORCE_HDMI_SYSTEM_AUDIO_ENFORCED))
device &= ~AUDIO_DEVICE_OUT_SPEAKER;
// for STRATEGY_SONIFICATION:
// if SPEAKER was selected, and SPEAKER_SAFE is available, use SPEAKER_SAFE instead
if ((strategy == STRATEGY_SONIFICATION) &&
(device & AUDIO_DEVICE_OUT_SPEAKER) &&
(availableOutputDevicesType & AUDIO_DEVICE_OUT_SPEAKER_SAFE))
device |= AUDIO_DEVICE_OUT_SPEAKER_SAFE;
device &= ~AUDIO_DEVICE_OUT_SPEAKER;
break;
return device;
-
如果是拨打电话状态,并且strategy等于STRATEGY_MEDIA,重新调用getDeviceForStrategyInt,strategy使用STRATEGY_PHONE。
-
判断可用输出设备,优先判断A2dp相关是否可用;
1. AUDIO_DEVICE_OUT_BLUETOOTH_A2DP 2. AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES(普通蓝牙耳机) 3. AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER(蓝牙音箱)
-
判断用户是否强制设置AUDIO_POLICY_FORCE_SPEAKER 扬声器;
-
按优先级排序
AUDIO_DEVICE_OUT_WIRED_HEADPHONE //普通 带线耳机 AUDIO_DEVICE_OUT_LINE AUDIO_DEVICE_OUT_WIRED_HEADSET //线控耳机 AUDIO_DEVICE_OUT_USB_HEADSET //usb耳机 AUDIO_DEVICE_OUT_USB_ACCESSORY AUDIO_DEVICE_OUT_USB_DEVICE //usb设备 AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET AUDIO_DEVICE_OUT_AUX_DIGITAL AUDIO_DEVICE_OUT_SPEAKER //扬声器
4. 选择设备、通路
audio_io_handle_t AudioPolicyManager::getOutputForDevice(
audio_devices_t device,
audio_session_t session,
audio_stream_type_t stream,
const audio_config_t *config,
audio_output_flags_t *flags)
audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
//direct output 相关处理 ......
if ((*flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0)
*flags = (audio_output_flags_t)(*flags | AUDIO_OUTPUT_FLAG_DIRECT);
//........
non_direct_output:
// A request for HW A/V sync cannot fallback to a mixed output because time
// stamps are embedded in audio data
if ((*flags & (AUDIO_OUTPUT_FLAG_HW_AV_SYNC | AUDIO_OUTPUT_FLAG_MMAP_NOIRQ)) != 0)
return AUDIO_IO_HANDLE_NONE;
// ignoring channel mask due to downmix capability in mixer
// open a non direct output
// for non direct outputs, only PCM is supported
if (audio_is_linear_pcm(config->format))
// get which output is suitable for the specified stream. The actual
// routing change will happen when startOutput() will be called
SortedVector<audio_io_handle_t> outputs = getOutputsForDevice(device, mOutputs);
// at this stage we should ignore the DIRECT flag as no direct output could be found earlier
*flags = (audio_output_flags_t)(*flags & ~AUDIO_OUTPUT_FLAG_DIRECT);
output = selectOutput(outputs, *flags, config->format);
return output;
通过flag 进行选择音频通路, Mixer或Direct,通常不设置的话,是Mixer 类通路。
直接看non_direct_output部分
- 对于FLAG_HW_AV_SYNC 请求,不能回退到混合输出,因为音频数据中嵌入了时间戳;
- 对于非直接输出(non direct outputs),只支持PCM;
- getOutputsForDevice 获取哪个输出适合指定的流。 实际的路由更改将在调用startOutput()时发生;
- selectOutput 从一组中通过优先级选择一个;
接着看getOutputsForDevice
SortedVector<audio_io_handle_t> AudioPolicyManager::getOutputsForDevice(
audio_devices_t device,
const SwAudioOutputCollection& openOutputs)
SortedVector<audio_io_handle_t> outputs;
ALOGVV("getOutputsForDevice() device %04x", device);
for (size_t i = 0; i < openOutputs.size(); i++)
ALOGVV("output %zu isDuplicated=%d device=%04x",
i, openOutputs.valueAt(i)->isDuplicated(),
openOutputs.valueAt(i)->supportedDevices());
if ((device & openOutputs.valueAt(i)->supportedDevices()) == device)
ALOGVV("getOutputsForDevice() found output %d", openOutputs.keyAt(i));
outputs.add(openOutputs.keyAt(i));
return outputs;
其中openOutputs是AudioPolicyManager::initialize加载hw module时进行添加的。通过遍历openOutputs,获取其支持对应device的所有audio_io_handle_t,并返回。
接着看selectOutput
audio_io_handle_t AudioPolicyManager::selectOutput(const SortedVector<audio_io_handle_t>& outputs,
audio_output_flags_t flags,
audio_format_t format)
// select one output among several that provide a path to a particular device or set of
// devices (the list was previously build by getOutputsForDevice()).
// The priority is as follows:
// 1: the output with the highest number of requested policy flags
// 2: the output with the bit depth the closest to the requested one
// 3: the primary output
// 4: the first output in the list
if (outputs.size() == 0)
return AUDIO_IO_HANDLE_NONE;
if (outputs.size() == 1)
return outputs[0];
int maxCommonFlags = 0;
audio_io_handle_t outputForFlags = AUDIO_IO_HANDLE_NONE;
audio_io_handle_t outputForPrimary = AUDIO_IO_HANDLE_NONE;
audio_io_handle_t outputForFormat = AUDIO_IO_HANDLE_NONE;
audio_format_t bestFormat = AUDIO_FORMAT_INVALID;
audio_format_t bestFormatForFlags = AUDIO_FORMAT_INVALID;
for (audio_io_handle_t output : outputs)
sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueFor(output);
if (!outputDesc->isDuplicated())
// if a valid format is specified, skip output if not compatible
if (format != AUDIO_FORMAT_INVALID)
if (outputDesc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT)
if (format != outputDesc->mFormat)
continue;
else if (!audio_is_linear_pcm(format))
continue;
if (AudioPort::isBetterFormatMatch(
outputDesc->mFormat, bestFormat, format))
outputForFormat = output;
bestFormat = outputDesc->mFormat;
int commonFlags = popcount(outputDesc->mProfile->getFlags() & flags);
if (commonFlags >= maxCommonFlags)
if (commonFlags == maxCommonFlags)
if (format != AUDIO_FORMAT_INVALID
&& AudioPort::isBetterFormatMatch(
outputDesc->mFormat, bestFormatForFlags, format))
outputForFlags = output;
bestFormatForFlags = outputDesc->mFormat;
else
outputForFlags = output;
maxCommonFlags = commonFlags;
bestFormatForFlags = outputDesc->mFormat;
ALOGV("selectOutput() commonFlags for output %d, %04x", output, commonFlags);
if (outputDesc->mProfile->getFlags() & AUDIO_OUTPUT_FLAG_PRIMARY)
outputForPrimary = output;
以上是关于Android 音频源码分析——AudioTrack设备选择的主要内容,如果未能解决你的问题,请参考以下文章
Android 音频源码分析——AudioTrack设备选择