【android telecom 框架分析 02】【CallAudioModeStateMachine介绍 1】【CallAudioModeStateMachine 整体介绍】

内容分享2天前发布
1 0 0


CallAudioModeStateMachine
是 Android AOSP 中负责管理电话音频模式的状态机。它根据当前通话状态(比如是否有来电、是否正在通话、是否是 VoIP 等)动态地切换 AudioManager 的音频模式,以便正确地处理音频焦点、铃声播放、通话音频等。


1. CallAudioModeStateMachine 的功能概述

这个类基于
StateMachine
构建,用于管理电话系统中音频焦点(Audio Focus)和音频模式(Audio Mode)的状态。它通过以下方式工作:

切换状态以适应通话生命周期:

来电响铃 → 正常通话 → 保持 → 通话结束

根据当前状态设置 AudioManager 的 Mode 和焦点
控制铃声、通话音频、处理特殊场景(如 VoIP、屏幕通话、音频处理等)


2. 状态详解

2.1
UnfocusedState
(未聚焦状态)

功能:

什么都不做,但占住状态。
只有等
AUDIO_OPERATIONS_COMPLETE
才真正释放 AudioFocus。
不会误释放导致音乐 app 抢到音频焦点。

场景举例: 电话应用未使用音频资源时(无通话), 或者初始状态就是 UnfocusedState。


// src/com/android/server/telecom/CallAudioModeStateMachine.java

    // CallAudioModeStateMachine 构造函数
    public CallAudioModeStateMachine(SystemStateHelper systemStateHelper,
            AudioManager audioManager, Looper looper) {
   
   
        ...

        createStates();
    }

    private void createStates() {
   
   
        addState(mUnfocusedState);
        addState(mRingingFocusState);
        addState(mSimCallFocusState);
        addState(mVoipCallFocusState);
        addState(mAudioProcessingFocusState);
        addState(mStreamingFocusState);
        addState(mOtherFocusState);
        setInitialState(mUnfocusedState); // 这里将 mUnfocusedState 设置为了初始化状态
        start();
        sendMessage(INITIALIZE, new MessageArgs.Builder()
                .setHasActiveOrDialingCalls(false)
                .setHasRingingCalls(false)
                .setHasHoldingCalls(false)
                .setIsTonePlaying(false)
                .setForegroundCallIsVoip(false)
                .setIsStreaming(false)
                .setSession(Log.createSubsession())
                .build());
    }


private class UnfocusedState extends BaseState {
   
   
        @Override
        public void enter() {
   
   
            Log.i(LOG_TAG, "Audio focus entering UNFOCUSED state");
            mLocalLog.log("Enter UNFOCUSED");
            if (mIsInitialized) {
   
   
                mCallAudioManager.setCallAudioRouteFocusState(CallAudioRouteStateMachine.NO_FOCUS);
                mAudioManager.setMode(AudioManager.MODE_NORMAL); // 这里会设置当前 Audio 为 MODE_NORMAL 状态, 代表:
                mLocalLog.log("Mode MODE_NORMAL");
                mMostRecentMode = AudioManager.MODE_NORMAL;
                // Don't release focus here -- wait until we get a signal that any other audio
                // operations triggered by this are done before releasing focus.
            }
        }

这里会设置当前 Audio 为 MODE_NORMAL 状态, 代表:

正常音频模式(非铃声状态且无通话建立),如音乐播放、视频播放等场景


1. 状态切换

        public boolean processMessage(Message msg) {
   
   
            if (super.processMessage(msg) == HANDLED) {
   
    // 这里会首先调用 BaseState.processMessage 处理, 如果 BaseState.processMessage 无法处理, 才会在 UnfocusedState.processMessage 中处理
                return HANDLED;
            }
            MessageArgs args = (MessageArgs) msg.obj;
            switch (msg.what) {
   
   
                case NO_MORE_ACTIVE_OR_DIALING_CALLS:
                    // Do nothing.
                    return HANDLED;
                case NO_MORE_RINGING_CALLS:
                    // Do nothing.
                    return HANDLED;
                case NO_MORE_HOLDING_CALLS:
                    // Do nothing.
                    return HANDLED;
                case NO_MORE_AUDIO_PROCESSING_CALLS:
                    // Do nothing.
                    return HANDLED;
                case NEW_ACTIVE_OR_DIALING_CALL: // 此时如果有活跃的电话,或者正在拨号
                    transitionTo(args.foregroundCallIsVoip
                            ? mVoipCallFocusState : mSimCallFocusState); // 如果是网络电话将 切换到 VoipCallFocusState , 如果是 普通的电话 切换到 SimCallFocusState
                    return HANDLED;
                case NEW_RINGING_CALL:
                    transitionTo(mRingingFocusState); // 如果此时来电 , 将切入 RingingFocusState
                    return HANDLED;
                case NEW_AUDIO_PROCESSING_CALL: // 有新的通话正在进行前处理, 将切入 AudioProcessingFocusState
                    transitionTo(mAudioProcessingFocusState);
                    return HANDLED;
                case NEW_HOLDING_CALL:
                    // This really shouldn't happen, but transition to the focused state anyway.
                    Log.w(LOG_TAG, "Call was surprisingly put into hold from an unknown state." +
                            " Args are: 
" + args.toString());
                    transitionTo(mOtherFocusState); // 有通话被保持 ,将进入 OtherFocusState
                    return HANDLED;
                case START_CALL_STREAMING:
                    transitionTo(mStreamingFocusState); // 开始音频流传输 ,将进入 StreamingFocusState
                    return HANDLED;
                case<
© 版权声明

相关文章

暂无评论

none
暂无评论...