Android系統分析之Audio音頻流, 音頻策略, 輸出設備之間的關系


音頻流, 音頻策略, 輸出設備之間的關系

只針對 AudioManager.STREAM_VOICE_CALL 音頻流類型進行分析

涉及到的類:

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

涉及到的方法及執行順序:

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

一. 通過音頻流的類型獲取對應的音頻策略

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;
    ...
    }
}

二. 通過音頻策略獲取到對應的輸出設備

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

三. 音頻流, 音頻策略, 輸出設備之間的關系

音頻的流類型決定音頻的策略, 音頻的策略決定輸出設備. 但是最終的輸出設備的確定, 受強制設置輸出設備影響.

四. 分析AudioManager.setSpeakerphoneOn(boolean on)方法, 查看強制設置對音頻輸出設備選擇的影響

涉及到的類及方法:

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;
    ... // 省略
    }
    ... // 省略
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM