Android 音频源码分析——AudioTrack设备选择

Posted VNanyesheshou

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 音频源码分析——AudioTrack设备选择相关的知识,希望对你有一定的参考价值。

Android 音频源码分析——AndroidRecord录音(一)
Android 音频源码分析——AndroidRecord录音(二)
Android 音频源码分析——AndroidRecord音频数据传输流程
Android 音频源码分析——audioserver启动
Android 音频源码分析——AudioFlinger
Android 音频源码分析——AudioTrack设备选择

基于Andorid9.0源码

以AudioTrack为例,梳理下输出设备选择流程。

音频设备选择的影响因素:

  1. AudioAttributes 声音流类型
  2. setForceUse 设置
  3. setPreferredDevice设置 (AudioRecord、AudioTrack、MediaRecorder、MediaPlayer)
  4. 等。。。。待研究

一、大多数情况输出设备选择

直接从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);    

  1. 通过AudioAttribute中的flags和usage获取对应的Stream type;
  2. AudioAttribute usage属性映射到strategy;
  3. 通过strategy 选择device类型;
  4. 选择音频设备、音频通路;

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);

  1. 检查是否存在与指定策略相对应的流类型的显示route请求,并优先于默认规则
  2. 是否从缓存中获取设备,这里framCache为false
  3. 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;

  1. 如果是拨打电话状态,并且strategy等于STRATEGY_MEDIA,重新调用getDeviceForStrategyInt,strategy使用STRATEGY_PHONE。

  2. 判断可用输出设备,优先判断A2dp相关是否可用;

    1. AUDIO_DEVICE_OUT_BLUETOOTH_A2DP
    2. AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES(普通蓝牙耳机)
    3. AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER(蓝牙音箱)
    
  3. 判断用户是否强制设置AUDIO_POLICY_FORCE_SPEAKER 扬声器;

  4. 按优先级排序

    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部分

  1. 对于FLAG_HW_AV_SYNC 请求,不能回退到混合输出,因为音频数据中嵌入了时间戳
  2. 对于非直接输出(non direct outputs),只支持PCM;
  3. getOutputsForDevice 获取哪个输出适合指定的流。 实际的路由更改将在调用startOutput()时发生;
  4. 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设备选择

Android 音频源码分析——AudioTrack设备选择

Android 音频源码分析——audioserver启动

Android 音频源码分析——音频设备切换(插入耳机)

Android 音频源码分析——音频设备切换(插入耳机)

Android 音频源码分析——音频设备切换(插入耳机)