Android 音频策略(音频优先级,音频输入输入,声音优先级)

1、音频设备

音频设备(/system/core/include/system/audio.h

enum {
    AUDIO_DEVICE_NONE                          = 0x0,
    /* reserved bits */
    AUDIO_DEVICE_BIT_IN                        = 0x80000000,
    AUDIO_DEVICE_BIT_DEFAULT                   = 0x40000000,
    /* output devices */这些是输出声音的设备,就是我们听声音的设备
    AUDIO_DEVICE_OUT_EARPIECE                  = 0x1,    // 听筒
    AUDIO_DEVICE_OUT_SPEAKER                   = 0x2,    // 扬声器
    AUDIO_DEVICE_OUT_WIRED_HEADSET             = 0x4,    // 线控耳机,可以通过耳机控制远端播放、暂停、音量调节等功能的耳机
    AUDIO_DEVICE_OUT_WIRED_HEADPHONE           = 0x8,    // 普通耳机,只能听,不能操控播放
    AUDIO_DEVICE_OUT_BLUETOOTH_SCO             = 0x10,   // 单声道蓝牙耳机,十进制16
    AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET     = 0x20,   // 车载免提蓝牙设备,十进制32
    AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT      = 0x40,   // 立体声蓝牙耳机,十进制64
    AUDIO_DEVICE_OUT_BLUETOOTH_A2DP            = 0x80,   // 蓝牙耳机
    AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES = 0x100,  // 十进制256
    AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER    = 0x200,  // 十进制512
    AUDIO_DEVICE_OUT_AUX_DIGITAL               = 0x400,  // HDMI输出
    AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET         = 0x800,  // 十进制2048
    AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET         = 0x1000, // 十进制4096
    AUDIO_DEVICE_OUT_USB_ACCESSORY             = 0x2000,
    AUDIO_DEVICE_OUT_USB_DEVICE                = 0x4000, //USB设备
    AUDIO_DEVICE_OUT_REMOTE_SUBMIX             = 0x8000,
    AUDIO_DEVICE_OUT_DEFAULT                   = AUDIO_DEVICE_BIT_DEFAULT,
    /* input devices */ (这里主要是接收声音的设备就是我们对着说话的设备)
    AUDIO_DEVICE_IN_COMMUNICATION         = AUDIO_DEVICE_BIT_IN | 0x1,
    AUDIO_DEVICE_IN_AMBIENT               = AUDIO_DEVICE_BIT_IN | 0x2,
    AUDIO_DEVICE_IN_BUILTIN_MIC           = AUDIO_DEVICE_BIT_IN | 0x4,  //手机自带MIC
    AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET = AUDIO_DEVICE_BIT_IN | 0x8,     //蓝牙耳机
    AUDIO_DEVICE_IN_WIRED_HEADSET         = AUDIO_DEVICE_BIT_IN | 0x10,  //3.5MM线性耳机
    AUDIO_DEVICE_IN_AUX_DIGITAL           = AUDIO_DEVICE_BIT_IN | 0x20,
    AUDIO_DEVICE_IN_VOICE_CALL            = AUDIO_DEVICE_BIT_IN | 0x40,
    AUDIO_DEVICE_IN_BACK_MIC              = AUDIO_DEVICE_BIT_IN | 0x80,
    AUDIO_DEVICE_IN_REMOTE_SUBMIX         = AUDIO_DEVICE_BIT_IN | 0x100,
    AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET     = AUDIO_DEVICE_BIT_IN | 0x200,
    AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET     = AUDIO_DEVICE_BIT_IN | 0x400,
    AUDIO_DEVICE_IN_USB_ACCESSORY         = AUDIO_DEVICE_BIT_IN | 0x800,
    AUDIO_DEVICE_IN_USB_DEVICE            = AUDIO_DEVICE_BIT_IN | 0x1000,   //USB耳机
    AUDIO_DEVICE_IN_DEFAULT               = AUDIO_DEVICE_BIT_IN | AUDIO_DEVICE_BIT_DEFAULT,
};

注意:这些设备比较常用的就是HDMI,扬声器,3.5mm圆孔耳机,USB耳机,还有蓝牙耳机。本文也主要针对这些设备的输入和输出策略做出说明。

2、音频策略

Android音频策略主要是在 frameworks/av/services/audiopolicy/enginedefault/src/Engine.cpp中,接下来我们看一下如何根据自己的需求在这个文件中调整自己的 音频输入输出策略。

2.1、音频输出策略

音频输出策略是在Engine::getDeviceForStrategyInt这个函数里面:我们主要捡重要的讲

DeviceVector Engine::getDevicesForStrategyInt(legacy_strategy strategy,
                                              DeviceVector availableOutputDevices,
                                              DeviceVector availableInputDevices,
                                              const SwAudioOutputCollection &outputs) const
{
 DeviceVector devices;
 switch (strategy) {         //这个函数就是在我们播放声音的时候,他负责选择合适的音频输出策略,
                            //所以这里开头就是一个Switch来进行选择
     case STRATEGY_TRANSMITTED_THROUGH_SPEAKER:
          ........
     case STRATEGY_SONIFICATION_RESPECTFUL:
          ........
     case STRATEGY_DTMF:
          ........
     case STRATEGY_PHONE:      //这个是比较重要的一个 ,我们在进行腾讯会议,或者打电话通话的时候(也就是语音通话)
                               //一句话:语音通话的声音输出走这个策略
        // Force use of only devices on primary output if:
        // - in call AND
        //   - cannot route from voice call RX OR
        //   - audio HAL version is < 3.0 and TX device is on the primary HW module
        ....省略不重要信息
        // for phone strategy, we first consider the forced use and then the available devices by
        // order of priority
         switch (getForceUse(AUDIO_POLICY_FORCE_FOR_COMMUNICATION)) {
        case AUDIO_POLICY_FORCE_BT_SCO:(蓝牙通话的时候输出会走这里)
            if (!isInCall() || strategy != STRATEGY_DTMF) {
                devices = availableOutputDevices.getDevicesFromType(
                        AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT);
                if (!devices.isEmpty()) break;
            }
            devices = availableOutputDevices.getFirstDevicesFromTypes({
                    AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET, AUDIO_DEVICE_OUT_BLUETOOTH_SCO});
            注意:上面这行就是常用选择设备函数,都是后面会出现很多这样的形式,这个也是我们调整策略必须要操作的

            if (!devices.isEmpty()) break;
            // if SCO device is requested but no SCO device is available, fall back to default case
            FALLTHROUGH_INTENDED;

        default:    // FORCE_NONE(如果不是蓝牙通话)
            devices = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_HEARING_AID);
            if (!devices.isEmpty()) break;
            // when not in a phone call, phone strategy should route STREAM_VOICE_CALL to A2DP
            if (!isInCall() &&
                    (getForceUse(AUDIO_POLICY_FORCE_FOR_MEDIA) != AUDIO_POLICY_FORCE_NO_BT_A2DP) &&
                     outputs.isA2dpSupported()) {
                devices = availableOutputDevices.getFirstDevicesFromTypes({
                        AUDIO_DEVICE_OUT_BLUETOOTH_A2DP,
                        AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES});
                if (!devices.isEmpty()) break;
            }
            devices = availableOutputDevices.getFirstDevicesFromTypes({
                    AUDIO_DEVICE_OUT_WIRED_HEADPHONE, AUDIO_DEVICE_OUT_WIRED_HEADSET,
                    AUDIO_DEVICE_OUT_LINE, AUDIO_DEVICE_OUT_USB_HEADSET,
                    AUDIO_DEVICE_OUT_USB_DEVICE});
            //这句就是关键啦,如果你想调整你的音频策略就在这个列表里面去调整,这里就明确了优先级:
         带mic耳机>不带麦的耳机>USB耳机   意思就是如果你同时插着USB耳机和圆孔耳机,然后你又是在打电话,
         ,声音就从圆孔耳机走了。


重点:如果你想调整音频策略怎么做?直接调整列表里的类型顺序就好啦


          ......
        }
    break;

    case STRATEGY_SONIFICATION:
             ............
    case STRATEGY_ENFORCED_AUDIBLE:
             ..........
    case STRATEGY_ACCESSIBILITY:
             ..........
    case STRATEGY_REROUTING:
             ..........
    case STRATEGY_MEDIA: {         //重点又来啦,这里是播放媒体声音时走的策略
        DeviceVector devices2;
        ........
        .......
        前面省略的都是一堆forceuse,如果没有设置强制使用,那么就走到这句,看到没,用扬声器输出啊
        if (devices2.isEmpty()) {
            devices2 = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_SPEAKER);
        }
        //如果你想要调整音频策略,就照着这个写把列表里的字段换成你想要的设备然后往前面放就好了,他是按照顺序向下执行
的,如果device2有了设备后面的就不执行了。

        DeviceVector devices3;
        if (strategy == STRATEGY_MEDIA) {
            // ARC, SPDIF and AUX_LINE can co-exist with others.
            devices3 = availableOutputDevices.getDevicesFromTypes({
                    AUDIO_DEVICE_OUT_HDMI_ARC, AUDIO_DEVICE_OUT_SPDIF, AUDIO_DEVICE_OUT_AUX_LINE});
        }

        devices2.add(devices3);
        // device is DEVICE_OUT_SPEAKER if we come from case STRATEGY_SONIFICATION or
        // STRATEGY_ENFORCED_AUDIBLE, AUDIO_DEVICE_NONE otherwise
        devices.add(devices2);

        // If hdmi system audio mode is on, remove speaker out of output list. //这里是HDMI输出我们是可以设置HDMI
和扬声器同时输出的,就是在最后面可以或device2 | 多个设备。
        if ((strategy == STRATEGY_MEDIA) &&
            (getForceUse(AUDIO_POLICY_FORCE_FOR_HDMI_SYSTEM_AUDIO) ==
                AUDIO_POLICY_FORCE_HDMI_SYSTEM_AUDIO_ENFORCED)) {
            devices.remove(devices.getDevicesFromType(AUDIO_DEVICE_OUT_SPEAKER));
        }
       
        }
        } break;

    case STRATEGY_CALL_ASSISTANT:

    default:
        ALOGW("getDevicesForStrategy() unknown strategy: %d", strategy);
        break;
    }

    if (devices.isEmpty()) {
        ALOGV("getDevicesForStrategy() no device found for strategy %d", strategy);
        sp<DeviceDescriptor> defaultOutputDevice = getApmObserver()->getDefaultOutputDevice();
        if (defaultOutputDevice != nullptr) {
            devices.add(defaultOutputDevice);
        }
        ALOGE_IF(devices.isEmpty(),
                 "getDevicesForStrategy() no default device defined");
    }
    ALOGVV("getDevices ForStrategy() strategy %d, device %s",
           strategy, dumpDeviceTypes(devices.types()).c_str());
    return devices;
}

这里就结束了音频的输出策略

2.2、音频输入策略

音频输出策略是在Engine::getDeviceForInputSource这个函数里面:我们主要捡重要的讲

sp<DeviceDescriptor> Engine::getDeviceForInputSource(audio_source_t inputSource) const
{
    const DeviceVector availableOutputDevices = getApmObserver()->getAvailableOutputDevices();
    const DeviceVector availableInputDevices = getApmObserver()->getAvailableInputDevices();
    const SwAudioOutputCollection &outputs = getApmObserver()->getOutputs();
    DeviceVector availableDevices = availableInputDevices;
    sp<AudioOutputDescriptor> primaryOutput = outputs.getPrimaryOutput();
    DeviceVector availablePrimaryDevices = primaryOutput == nullptr ? DeviceVector()
            : availableInputDevices.getDevicesFromHwModule(primaryOutput->getModuleHandle());
    sp<DeviceDescriptor> device;

    // when a call is active, force device selection to match source VOICE_COMMUNICATION
    // for most other input sources to avoid rerouting call TX audio
    if (isInCall()) {
        switch (inputSource) {
        case AUDIO_SOURCE_DEFAULT:
        case AUDIO_SOURCE_MIC:  //一般会走到这里
        case AUDIO_SOURCE_VOICE_RECOGNITION:
        case AUDIO_SOURCE_UNPROCESSED:
        case AUDIO_SOURCE_HOTWORD:
        case AUDIO_SOURCE_CAMCORDER:
        case AUDIO_SOURCE_VOICE_PERFORMANCE:
            inputSource = AUDIO_SOURCE_VOICE_COMMUNICATION;   //也会走这个策略
            break;
        default:
            break;
        }
    }

    switch (inputSource) {
    case AUDIO_SOURCE_DEFAULT:
    case AUDIO_SOURCE_MIC:
        device = availableDevices.getDevice(
                AUDIO_DEVICE_IN_BLUETOOTH_A2DP, String8(""), AUDIO_FORMAT_DEFAULT);
        if (device != nullptr) break;
        if (getForceUse(AUDIO_POLICY_FORCE_FOR_RECORD) == AUDIO_POLICY_FORCE_BT_SCO) {
            device = availableDevices.getDevice(
                    AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET, String8(""), AUDIO_FORMAT_DEFAULT);
            if (device != nullptr) break;
        }
        device = availableDevices.getFirstExistingDevice({
                AUDIO_DEVICE_IN_WIRED_HEADSET, AUDIO_DEVICE_IN_USB_HEADSET,
                AUDIO_DEVICE_IN_USB_DEVICE, AUDIO_DEVICE_IN_BUILTIN_MIC});
        //打电话应该就是走的mic输入,收录声音就是用的mic,但是可以从列表里面看出来如果有圆孔耳机或者USB耳机,圆孔耳机和
USB耳机的优先级是要比BUILTIN_MIC (麦克风)高的
        break;

    case AUDIO_SOURCE_VOICE_COMMUNICATION: //这个策略就是我们进行腾讯会议这类型语音通话类的app进行声音输入时走
的策略
        // Allow only use of devices on primary input if in call and HAL does not support routing
        // to voice call path.
        if ((getPhoneState() == AUDIO_MODE_IN_CALL) &&
                (availableOutputDevices.getDevice(AUDIO_DEVICE_OUT_TELEPHONY_TX,
                        String8(""), AUDIO_FORMAT_DEFAULT)) == nullptr) {
            LOG_ALWAYS_FATAL_IF(availablePrimaryDevices.isEmpty(), "Primary devices not found");
            availableDevices = availablePrimaryDevices;
        }

        switch (getForceUse(AUDIO_POLICY_FORCE_FOR_COMMUNICATION)) {
        case AUDIO_POLICY_FORCE_BT_SCO:
            // if SCO device is requested but no SCO device is available, fall back to default case
            device = availableDevices.getDevice(
                    AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET, String8(""), AUDIO_FORMAT_DEFAULT);
            if (device != nullptr) {
                break;
            }
            FALLTHROUGH_INTENDED;

        default:    // FORCE_NONE
            device = availableDevices.getFirstExistingDevice({
                    AUDIO_DEVICE_IN_WIRED_HEADSET, AUDIO_DEVICE_IN_USB_HEADSET,
                    AUDIO_DEVICE_IN_USB_DEVICE, AUDIO_DEVICE_IN_BUILTIN_MIC});
           //起决定性作用的还是这里,如果想要修改顺序,调整列表里的设备即可
            break;

        case AUDIO_POLICY_FORCE_SPEAKER:
            device = availableDevices.getFirstExistingDevice({
                    AUDIO_DEVICE_IN_BACK_MIC, AUDIO_DEVICE_IN_BUILTIN_MIC});
            break;
        }
        break;

    case AUDIO_SOURCE_VOICE_RECOGNITION:
    case AUDIO_SOURCE_UNPROCESSED:
    case AUDIO_SOURCE_HOTWORD:
    case AUDIO_SOURCE_CAMCORDER:
    case AUDIO_SOURCE_VOICE_DOWNLINK:
    case AUDIO_SOURCE_VOICE_CALL:
    case AUDIO_SOURCE_VOICE_UPLINK:
    case AUDIO_SOURCE_VOICE_PERFORMANCE:
    case AUDIO_SOURCE_REMOTE_SUBMIX:
    case AUDIO_SOURCE_FM_TUNER:
    case AUDIO_SOURCE_ECHO_REFERENCE:
    default:
        ALOGW("getDeviceForInputSource() invalid input source %d", inputSource);
        break;
    }
    if (device == nullptr) {
        ALOGV("getDeviceForInputSource() no device found for source %d", inputSource);
        device = availableDevices.getDevice(
                AUDIO_DEVICE_IN_STUB, String8(""), AUDIO_FORMAT_DEFAULT);
        ALOGE_IF(device == nullptr,
                 "getDeviceForInputSource() no default device defined");
    }
    ALOGV_IF(device != nullptr,
             "getDeviceForInputSource()input source %d, device %08x",
             inputSource, device->type());
    return device;
}

这里做了后插优先,就是那个设备最后插入声音就从哪个设备走,包括输入和输出,主要就是通过获取最后插入的设备类型来动态的调整声音优先级即可

猜你喜欢

转载自blog.csdn.net/u010823818/article/details/131241993
今日推荐