getOutputForAttr解析

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三部曲

  1. getAudioAttributes 、getStreamTypeForAttributes
  • 根据输入attr参数到Engine模块去确定音频StreamType属性
    确定规则主要对比使用输入参数attr的与ProductStrategy的attr对比,依次对比contentType、usage等,相等就选择该ProductStrategy的配置streamType。(其实这里通过attr的几个参数(usage/content-type/flag)基本上就是确认唯一的streamType和ProductStrategy)
  1. getOutputDevicesForAttributes
  • 根据输入attr(usage/content-type/flag)参数去Engine模块确定devices设备
    • 首先通过attr找到ProcuctStrategy(再根据属性获取声音的Strategy,Strategy就是声音的类别)
  • -通过ProcuctStrategy策略去匹配不同的设备(其实这里就是多个case情况,本身是根据策略的不同,匹配设备的规则也就是不同)一般是以下这个规则:蓝牙设备->有线连接设备(如耳机)->usb连接设备->自带的音频设备,最后就找到了输出设备DeviceVector
  1. 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就是我们需要的
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值