The relationship between the audio stream, audio strategies, analysis of the output device Android system Audio

The relationship between the audio stream, audio strategies, output devices

Only analyzed for AudioManager.STREAM_VOICE_CALL audio stream type

Related to the class:

hardware/libhardware_legacy/audio/AudioPolicyManagerBase.cpp
frameworks/base/media/java/android/media/AudioManager.java
frameworks/base/media/java/android/media/AudioService.java
frameworks/base/media/java/android/media/AudioSystem.java

It relates to a method and order of execution:

AudioPolicyManagerBase.getStrategy(AudioSystem::stream_type stream);
AudioPolicyManagerBase.getDeviceForStrategy(routing_strategy strategy, bool fromCache);

A. Corresponding audio acquisition strategy by the type of audio stream

AudioPolicyManagerBase.cpp:

AudioPolicyManagerBase::routing_strategy AudioPolicyManagerBase::getStrategy(AudioSystem::stream_type stream) {
    // stream to strategy mapping
    switch (stream) {
    case AudioSystem::VOICE_CALL:
    case AudioSystem::BLUETOOTH_SCO:
        return STRATEGY_PHONE;
    ...
    }
}

II. Obtained by the corresponding audio output device policy

AudioPolicyManagerBase.cpp:

audio_devices_t AudioPolicyManagerBase::getDeviceForStrategy(routing_strategy strategy, bool fromCache) {
    uint32_t device = AUDIO_DEVICE_NONE;
    ... // 省略
    switch (strategy) {
    ... // 省略
    case STRATEGY_PHONE:
        // for phone strategy, we first consider the forced use and then the available devices by order
        // of priority
        switch (mForceUse[AudioSystem::FOR_COMMUNICATION]) { // 判断是否有设置在通讯过程中, 强制使用某种输出设备
        case AudioSystem::FORCE_BT_SCO: // 强制使用蓝牙, 作为输出设备
            if (!isInCall() || strategy != STRATEGY_DTMF) {
                device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
                if (device) break;
            }
            device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
            if (device) break;
            device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_SCO;
            if (device) break;
            // if SCO device is requested but no SCO device is available, fall back to default case
            // FALL THROUGH

        default:    // FORCE_NONE 没有设置通讯过程中, 强制使用某种输出设备
            // when not in a phone call, phone strategy should route STREAM_VOICE_CALL to A2DP
            if (mHasA2dp && !isInCall() &&
                    (mForceUse[AudioSystem::FOR_MEDIA] != AudioSystem::FORCE_NO_BT_A2DP) &&
                    (getA2dpOutput() != 0) && !mA2dpSuspended) {
                device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP;
                if (device) break;
                device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES;
                if (device) break;
            }
            device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE;
            if (device) break;
            device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_WIRED_HEADSET;
            if (device) break;
            if (mPhoneState != AudioSystem::MODE_IN_CALL) {
                device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_ACCESSORY;
                if (device) break;
                device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_DEVICE;
                if (device) break;
                device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET;
                if (device) break;
                device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_AUX_DIGITAL;
                if (device) break;
                device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET;
                if (device) break;
            }
            // 没有设置通讯过程中, 音频的输出设备, 则默认使用听筒作为输出设备
            device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_EARPIECE;
            if (device) break;
            device = mDefaultOutputDevice;
            if (device == AUDIO_DEVICE_NONE) {
                ALOGE("getDeviceForStrategy() no device found for STRATEGY_PHONE");
            }
            break;

        case AudioSystem::FORCE_SPEAKER: // 强制使用扬声器, 作为输出设备
            // when not in a phone call, phone strategy should route STREAM_VOICE_CALL to
            // A2DP speaker when forcing to speaker output
            if (mHasA2dp && !isInCall() &&
                    (mForceUse[AudioSystem::FOR_MEDIA] != AudioSystem::FORCE_NO_BT_A2DP) &&
                    (getA2dpOutput() != 0) && !mA2dpSuspended) {
                device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER;
                if (device) break;
            }
            if (mPhoneState != AudioSystem::MODE_IN_CALL) {
                device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_ACCESSORY;
                if (device) break;
                device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_DEVICE;
                if (device) break;
                device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET;
                if (device) break;
                device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_AUX_DIGITAL;
                if (device) break;
                device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET;
                if (device) break;
            }
            device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_SPEAKER;
            if (device) break;
            device = mDefaultOutputDevice;
            if (device == AUDIO_DEVICE_NONE) {
                ALOGE("getDeviceForStrategy() no device found for STRATEGY_PHONE, FORCE_SPEAKER");
            }
            break;
        }
    break;
    // 关于上面default位置的问题, 如果每个case选择(包括default)最终都有break语句, 则default的位置不影响执行顺序
    // 当每个case选择(包括default)不一定有break语句时, 如果输入不满足其他选择, 最终执行default. 程序会从default处从上向下执行, 直到遇到break语句停止
    // 此处的default位置并不影响执行顺序
    ... // 省略
    }
    return device;
}

III. The relationship between the audio stream, audio strategies, output devices

Policy decisions audio stream type of audio, the audio output device policy decisions, but to determine the final output device, the output device is affected by the forced settings.

IV. Analysis AudioManager.setSpeakerphoneOn (boolean on) method, see the mandatory impact on the selection of the audio output device settings

It relates to the class and method:

1. AudioManager.setSpeakerphoneOn(boolean on);
2. AudioService.setSpeakerphoneOn(boolean on);
3. AudioService.AudioHandler.setForceUse(int usage, int config);
4. AudioSystem.setForceUse(int usage, int config);
5. AudioPolicyManagerBase.setForceUse(AudioSystem::force_use usage, AudioSystem::forced_config config);

4.1. AudioManager.java:
public void setSpeakerphoneOn(boolean on){
    IAudioService service = getService();
    service.setSpeakerphoneOn(on);
}

4.2. AudioService.java:
public void setSpeakerphoneOn(boolean on){
    if (on) {
        if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
                sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
                        AudioSystem.FOR_RECORD, AudioSystem.FORCE_NONE, null, 0);
        }
        mForcedUseForComm = AudioSystem.FORCE_SPEAKER;
    } else if (mForcedUseForComm == AudioSystem.FORCE_SPEAKER){
        mForcedUseForComm = AudioSystem.FORCE_NONE;
    }
    // 从此处可以看到 setSpeakerphoneOn(boolean on) 只针对 AudioSystem.FOR_COMMUNICATION 有效
    // 而 AudioSystem.FOR_COMMUNICATION 最终影响到的是输出设备的选择
    sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
            AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0);
}

private class AudioHandler extends Handler {
    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
        case MSG_SET_FORCE_USE:
        case MSG_SET_FORCE_BT_A2DP_USE:
            setForceUse(msg.arg1, msg.arg2);
            break;
        }
    }
    private void setForceUse(int usage, int config) {
        AudioSystem.setForceUse(usage, config);
    }       
}

4.3. AudioSystem.java:
public static native int setForceUse(int usage, int config);

4.4. AudioPolicyManagerBase.cpp:
void AudioPolicyManagerBase::setForceUse(AudioSystem::force_use usage, AudioSystem::forced_config config) {
    bool forceVolumeReeval = false;
    switch(usage) {
    case AudioSystem::FOR_COMMUNICATION:
        if (config != AudioSystem::FORCE_SPEAKER && config != AudioSystem::FORCE_BT_SCO &&
            config != AudioSystem::FORCE_NONE) {
            ALOGW("setForceUse() invalid config %d for FOR_COMMUNICATION", config);
            return;
        }
        forceVolumeReeval = true;
        // 保存设置到数组中, 最终在 getDeviceForStrategy(routing_strategy strategy, bool fromCache) 中被调用
        mForceUse[usage] = config;
        break;
    ... // 省略
    }
    ... // 省略
}

Guess you like

Origin www.cnblogs.com/firmly-believe/p/10991077.html
Recommended