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,
const AttributionSourceState& attributionSource,
const audio_config_t *config,
audio_output_flags_t *flags,
audio_port_handle_t *selectedDeviceId,
audio_port_handle_t *portId,
std::vector<audio_io_handle_t> *secondaryOutputs,
output_type_t *outputType)
{
audio_attributes_t resultAttr;
status_t status = getOutputForAttrInt(&resultAttr, output, session, attr, stream, uid,
config, flags, selectedDeviceId, &isRequestedDeviceForExclusiveUse,
secondaryOutputs != nullptr ? &secondaryMixes : nullptr, outputType);
audio_config_base_t clientConfig = {.sample_rate = config->sample_rate,
.channel_mask = config->channel_mask,
.format = config->format,
};
*portId = PolicyAudioPort::getNextUniqueId();
sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueFor(*output);
sp<TrackClientDescriptor> clientDesc =
new TrackClientDescriptor(*portId, uid, session, resultAttr, clientConfig,
sanitizedRequestedPortId, *stream,
mEngine->getProductStrategyForAttributes(resultAttr),
toVolumeSource(resultAttr),
*flags, isRequestedDeviceForExclusiveUse,
std::move(weakSecondaryOutputDescs),
outputDesc->mPolicyMix);
outputDesc->addClient(clientDesc);
return NO_ERROR;
}
status_t AudioPolicyManager::getOutputForAttrInt(
audio_attributes_t *resultAttr,
audio_io_handle_t *output,
audio_session_t session,
const audio_attributes_t *attr,
audio_stream_type_t *stream,
uid_t uid,
const audio_config_t *config,
audio_output_flags_t *flags,
audio_port_handle_t *selectedDeviceId,
bool *isRequestedDeviceForExclusiveUse,
std::vector<sp<AudioPolicyMix>> *secondaryMixes,
output_type_t *outputType)
{
DeviceVector outputDevices;
const audio_port_handle_t requestedPortId = *selectedDeviceId;
DeviceVector msdDevices = getMsdAudioOutDevices();
const sp<DeviceDescriptor> requestedDevice =
mAvailableOutputDevices.getDeviceFromId(requestedPortId);
*outputType = API_OUTPUT_INVALID;
//如果attr为空,那么就根据stream_type找到对应的audio_attributes_t赋值给resultAttr
status_t status = getAudioAttributes(resultAttr, attr, *stream);//将attr赋值给resultAttr
//
*stream = mEngine->getStreamTypeForAttributes(*resultAttr);
//省略
outputDevices = mEngine->getOutputDevicesForAttributes(*resultAttr, requestedDevice, false);//根据resultAttr,找到device
//省略
if (*output == AUDIO_IO_HANDLE_NONE) {
*output = getOutputForDevices(outputDevices, session, *stream, config,
flags, resultAttr->flags & AUDIO_FLAG_MUTE_HAPTIC);//根据device,找到output
}
//省略
}
1.1 第一步 AudioAttributes
将入参attr,赋值给resultAttr,如果没有,则根据stream类型查找默认值(audio_policy_engine_product_strategies.xml解析而来,
目前使用gDefaultEngineConfig)
1.2 getStreamTypeForAttributes
1 . 遍历每一个ProductStrategy
2 . 遍历每一个ProductStrategy内的Attribute;
3 . 将attr中的参数与Attrbutes内的usage、contentType,flag注逐一对比,返回对应的streamType(其实这里就能确定唯一的streamType) (默认值是AUDIO_STREAM_MUSIC)
2 第二步 getOutputDevicesForAttributes
DeviceVector Engine::getOutputDevicesForAttributes(const audio_attributes_t &attributes,
const sp<DeviceDescriptor> &preferredDevice,
bool fromCache) const
{
//根据attributes,找到对应的strategy
product_strategy_t strategy = getProductStrategyForAttributes(attributes);
const DeviceVector availableOutputDevices = getApmObserver()->getAvailableOutputDevices();
const SwAudioOutputCollection &outputs = getApmObserver()->getOutputs();
//
// @TODO: what is the priority of explicit routing? Shall it be considered first as it used to
// be by APM?
//
// Honor explicit routing requests only if all active clients have a preferred route in which
// case the last active client route is used
sp<DeviceDescriptor> device = findPreferredDevice(outputs, strategy, availableOutputDevices);
if (device != nullptr) {
return DeviceVector(device);
}
return fromCache? mDevicesForStrategies.at(strategy) : getDevicesForProductStrategy(strategy);
}
DeviceVector Engine::getDevicesForProductStrategy(product_strategy_t strategy) const {
return getDevicesForStrategyInt(legacyStrategy,
availableOutputDevices,
outputs);
}
DeviceVector Engine::getDevicesForStrategyInt(legacy_strategy strategy,
DeviceVector availableOutputDevices,
const SwAudioOutputCollection &outputs) const
{
DeviceVector devices;
switch (strategy)
{
···
case STRATEGY_TRANSMITTED_THROUGH_SPEAKER:
devices = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_SPEAKER);
break;
case STRATEGY_MEDIA:
{
···
}
break;
default:
ALOGW("%s unknown strategy: %d", __func__, strategy);
break;
}
return devices;
getDevicesForStrategyInt 里面是大量的case判断通过传入的strategy 找到对应的case,然后在通过以下规则来找到合适的deviec,举例STRATEGY_MEDIA
设备优先级 蓝牙设备>有限连接设备(耳机)>usb连接设备>自带的音频设备
3 第三步 getOutputForDevices
audio_io_handle_t AudioPolicyManager::getOutputForDevices(
const DeviceVector &devices,
audio_session_t session,
audio_stream_type_t stream,
const audio_config_t *config,
audio_output_flags_t *flags,
bool forceMutingHaptic)
{
audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
···
audio_config_t directConfig = *config;
directConfig.channel_mask = channelMask;
//如果是AUDIO_OUTPUT_FLAG_DIRECT /AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD 会重新创建一个输出通道
status_t status = openDirectOutput(stream, session, &directConfig, *flags, devices, &output);
if (status != NAME_NOT_FOUND) {
return 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
//mOutput是SwAudioOutputCollection 里面是根据audio_io_handle_t为key SwAudioOutputDescriptor为value,那么audio_io_handle_t其实就是创建完线程的output_id
//我们查看mOutput是SwAudioOutputCollection 有哪些是支持devices的。然后返回audio_io_handle_t结合
SortedVector<audio_io_handle_t> outputs = getOutputsForDevices(devices, 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);
//然后在通过flags 与音频信息获取到最合适的那个output_id
output = selectOutput(
outputs, *flags, config->format, channelMask, config->sample_rate, session);
}
ALOGW_IF((output == 0), "getOutputForDevices() could not find output for stream %d, "
"sampling rate %d, format %#x, channels %#x, flags %#x",
stream, config->sample_rate, config->format, channelMask, *flags);
return output;
}
4 总结
getOutputForAttr三部曲
- getAudioAttributes 、getStreamTypeForAttributes
- 根据输入attr参数到Engine模块去确定音频StreamType属性
确定规则主要对比使用输入参数attr的与ProductStrategy的attr对比,依次对比contentType、usage等,相等就选择该ProductStrategy的配置streamType。(其实这里通过attr的几个参数(usage/content-type/flag)基本上就是确认唯一的streamType和ProductStrategy)
- getOutputDevicesForAttributes
- 根据输入attr(usage/content-type/flag)参数去Engine模块确定devices设备
-
- 首先通过attr找到ProcuctStrategy(再根据属性获取声音的Strategy,Strategy就是声音的类别)
- -通过ProcuctStrategy策略去匹配不同的设备(其实这里就是多个case情况,本身是根据策略的不同,匹配设备的规则也就是不同)一般是以下这个规则:蓝牙设备->有线连接设备(如耳机)->usb连接设备->自带的音频设备,最后就找到了输出设备DeviceVector
- getOutputForDevices
- 根据前两步骤得到的streamType、DeviceVector确认输入通道output
注意对于flag = AUDIO_OUTPUT_FLAG_DIRECT /AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD情况是从新创建一个新的输出通道 接下来分析是进程启动时就创建好的输出通道如primary_out、low_latency、deep_buffer. -
- 首先函数getOutputsForDevices会遍历SwAudioOutputCollection,找到支持当前device的SwAudioOutputDescriptor的key值
-
- 然后函数selectOutput 会根据传参flags、format、channleMask、sample_rate来确定一个最合适的SwAudioOutputDescriptor,那么这个SwAudioOutputDescriptor包含的output就是我们需要的