Android8上原生Audio 按键调节音量的流程

Android 当前调节音量有两方式:

  1. 在屏幕显示音量调节界面手动调节某种音频的音量:常见的多媒体,通话,提示铃声等
  2. 第二种就是直接通过音量物理按键进行调节当前的active 的音频音量的大小:

现在主要根据物理按键调节Audio音量的流程进行分析:

PhoneWindow.java#onKeyUp()/onKeyDown()
-->MediaSessionLegacyHelper.sendVolumeKeyEvent()
    -->MediaSessionManager.dispatchVolumeKeyEventP{
        -->MediaSessionService.dispatchVolumeKeyEvent()
            -->MediaSessionService.dispatchVolumeKeyEventLocked()
                -->MediaSessionService.dispatchAdjustVolumeLocked()
                    -->AudioService.adjustSuggestedStreamVolumeForUid()
                        -->AudioService.adjustSuggestedStreamVolume()

当物理按键被按下后,如果当前应用没有拦截并处理这个事件,PhoneWindow的onKeyDown()或onKeyUp()方法会处理此事件,在PhoneWindow的onKeyDoen() 有对当前有无会话流的判断,

        switch (keyCode) {
            case KeyEvent.KEYCODE_VOLUME_UP:
            case KeyEvent.KEYCODE_VOLUME_DOWN:
            case KeyEvent.KEYCODE_VOLUME_MUTE: {
                // If we have a session send it the volume command, otherwise
                // use the suggested stream.
                if (mMediaController != null) {
                    int direction = 0;
                    switch (keyCode) {
                        case KeyEvent.KEYCODE_VOLUME_UP:
                            direction = AudioManager.ADJUST_RAISE;
                            break;
                        case KeyEvent.KEYCODE_VOLUME_DOWN:
                            direction = AudioManager.ADJUST_LOWER;
                            break;
                        case KeyEvent.KEYCODE_VOLUME_MUTE:
                            direction = AudioManager.ADJUST_TOGGLE_MUTE;
                            break;
                    }
                    mMediaController.adjustVolume(direction, AudioManager.FLAG_SHOW_UI);
                } else {
                    MediaSessionLegacyHelper.getHelper(getContext()).sendVolumeKeyEvent(
                            event, mVolumeControlStreamType, false);
                }
                return true;
            }

若mMediaController != null,既当前无会话流,则使用suggesed stream.接下来调用MediaSessionLegacyHelperd的sendVolumeKeyEvent()方法,将按键事件往下传递:


    public void sendVolumeKeyEvent(KeyEvent keyEvent, int stream, boolean musicOnly) {
        if (keyEvent == null) {
            Log.w(TAG, "Tried to send a null key event. Ignoring.");
            return;
        }
        mSessionManager.dispatchVolumeKeyEvent(keyEvent, stream, musicOnly);
    }

sendVolumeKeyEvent()方法调用MediaSessionManager的dispatchVolumeKeyEvent()方法,顺着代码看可以看到:最终调到AudioService的adjustSuggestedStreamVolume()方法.


    private void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
            String callingPackage, String caller, int uid) {
        mVolumeLogger.log(new VolumeEvent(VolumeEvent.VOL_ADJUST_SUGG_VOL, suggestedStreamType,
                direction/*val1*/, flags/*val2*/, new StringBuilder(callingPackage)
                        .append("/").append(caller).append(" uid:").append(uid).toString()));
        final int streamType;
        synchronized (mForceControlStreamLock) {
            if (DEBUG_VOL) Log.d(TAG, "adjustSuggestedStreamVolume() stream=" + suggestedStreamType
                    + ", flags=" + flags + ", caller=" + caller
                    + ", volControlStream=" + mVolumeControlStream
                    + ", userSelect=" + mUserSelectedVolumeControlStream);
            if (mUserSelectedVolumeControlStream) { // implies mVolumeControlStream != -1
                streamType = mVolumeControlStream;
            } else {
                // 判断suggestedStream 是否是当前活动的音频流.
                final int maybeActiveStreamType = getActiveStreamType(suggestedStreamType);
                final boolean activeForReal;
                if (maybeActiveStreamType == AudioSystem.STREAM_MUSIC) {
                    activeForReal = isAfMusicActiveRecently(0);
                } else {
                    activeForReal = AudioSystem.isStreamActive(maybeActiveStreamType, 0);
                }
                // 在这里获取当前活动的音频流,进而控制当前活动的音频流.
                if (activeForReal || mVolumeControlStream == -1) {
                    streamType = maybeActiveStreamType;
                } else {
                    streamType = mVolumeControlStream;
                }
            }
        }
        // 判断是否是MUTE
        final boolean isMute = isMuteAdjust(direction);
        // 确认当前的流类型是有效的(代码中定义的,未定义的及非法的流类型)
        ensureValidStreamType(streamType);
        final int resolvedStream = mStreamVolumeAlias[streamType];

        // Play sounds on STREAM_RING only.
        if ((flags & AudioManager.FLAG_PLAY_SOUND) != 0 &&
                resolvedStream != AudioSystem.STREAM_RING) {
            flags &= ~AudioManager.FLAG_PLAY_SOUND;
        }

        // For notifications/ring, show the ui before making any adjustments
        // Don't suppress mute/unmute requests
        if (mVolumeController.suppressAdjustment(resolvedStream, flags, isMute)) {
            direction = 0;
            flags &= ~AudioManager.FLAG_PLAY_SOUND;
            flags &= ~AudioManager.FLAG_VIBRATE;
            if (DEBUG_VOL) Log.d(TAG, "Volume controller suppressed adjustment");
        }

        adjustStreamVolume(streamType, direction, flags, callingPackage, caller, uid);
    }

所以在adjustSuggestedStreamVolume()方法中确定要调节的流类型,并然后调用adjustStreamVolume()方法.

    private void adjustStreamVolume(int streamType, int direction, int flags,
            String callingPackage, String caller, int uid) {
        if (mUseFixedVolume) {
            return;
        }
            ..........
        // use stream type alias here so that streams with same alias have the same behavior,
        // including with regard to silent mode control (e.g the use of STREAM_RING below and in
        // checkForRingerModeChange() in place of STREAM_RING or STREAM_NOTIFICATION)
        int streamTypeAlias = mStreamVolumeAlias[streamType];

        VolumeStreamState streamState = mStreamStates[streamTypeAlias];

        final int device = getDeviceForStream(streamTypeAlias);
            ..........
            if (isMuteAdjust) {
                boolean state;
                if (direction == AudioManager.ADJUST_TOGGLE_MUTE) {
                    state = !streamState.mIsMuted;
                } else {
                    state = direction == AudioManager.ADJUST_MUTE;
                }
                if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
                    setSystemAudioMute(state);
                }
                for (int stream = 0; stream < mStreamStates.length; stream++) {
                    if (streamTypeAlias == mStreamVolumeAlias[stream]) {
                        if (!(readCameraSoundForced()
                                    && (mStreamStates[stream].getStreamType()
                                        == AudioSystem.STREAM_SYSTEM_ENFORCED))) {
                            mStreamStates[stream].mute(state);
                        }
                    }
                }
            } else if ((direction == AudioManager.ADJUST_RAISE) &&
                    !checkSafeMediaVolume(streamTypeAlias, aliasIndex + step, device)) {
                Log.e(TAG, "adjustStreamVolume() safe volume index = " + oldIndex);
                mVolumeController.postDisplaySafeVolumeWarning(flags);
            } else if (streamState.adjustIndex(direction * step, device, caller)
                    || streamState.mIsMuted) {
                // Post message to set system volume (it in turn will post a
                // message to persist).
                if (streamState.mIsMuted) {
                    // Unmute the stream if it was previously muted
                    if (direction == AudioManager.ADJUST_RAISE) {
                        // unmute immediately for volume up
                        streamState.mute(false);
                    } else if (direction == AudioManager.ADJUST_LOWER) {
                        if (mIsSingleVolume) {
                            sendMsg(mAudioHandler, MSG_UNMUTE_STREAM, SENDMSG_QUEUE,
                                    streamTypeAlias, flags, null, UNMUTE_STREAM_DELAY);
                        }
                    }
                }
                // sendMsg去设置音量
                sendMsg(mAudioHandler,
                        MSG_SET_DEVICE_VOLUME,
                        SENDMSG_QUEUE,
                        device,
                        0,
                        streamState,
                        0);
            }

            // Check if volume update should be sent to Hdmi system audio.
            int newIndex = mStreamStates[streamType].getIndex(device);
            if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
                setSystemAudioVolume(oldIndex, newIndex, getStreamMaxVolume(streamType), flags);
            }
            if (mHdmiManager != null) {
                synchronized (mHdmiManager) {
                    // mHdmiCecSink true => mHdmiPlaybackClient != null
                    if (mHdmiCecSink &&
                            streamTypeAlias == AudioSystem.STREAM_MUSIC &&
                            oldIndex != newIndex) {
                        synchronized (mHdmiPlaybackClient) {
                            int keyCode = (direction == -1) ? KeyEvent.KEYCODE_VOLUME_DOWN :
                                    KeyEvent.KEYCODE_VOLUME_UP;
                            final long ident = Binder.clearCallingIdentity();
                            try {
                                mHdmiPlaybackClient.sendKeyEvent(keyCode, true);
                                mHdmiPlaybackClient.sendKeyEvent(keyCode, false);
                            } finally {
                                Binder.restoreCallingIdentity(ident);
                            }
                        }
                    }
                }
            }
        }
        int index = mStreamStates[streamType].getIndex(device);
        // 通知修改UI的音量条变化
        sendVolumeUpdate(streamType, oldIndex, index, flags);
    }

(这里面的调用比较多,贴源码比较麻烦,还是参看/frameworks/base/services/core/java/com/android/server/audio/AudioService.java
)

在adjustStreamVolume里调用VolumeStreamState对象的adjustIndex()更改这个对象中保存的音量值;

VolumeStreamState类保存了一个流类型所有音量相关的信息,AudioService为每一种流类型都分配了一个VolumeStreamState对象,并以流类型的值为索引,保存在一个名为数组mStreamStates中;

在adjustStreamVolume方法中调用了VolumeStreamState对象的adjustIndex()方法,于是就改变了这个对象中存储的音量值,并通过sendBroadcastToAll方法发送广播通知外界音量发生变化。

通过sendMsg()发送消息MSG_SET_DEVICE_VOLUME到mAudioHandler 发送消息后会调用到mAudioHandler中负责处理MSG_SET_DEVICE_VOLUME消息的setDeviceVolume方法,此方法最后会调用AudioSystem.setStreamVolumeIndex方法将音量设置到底层的AudioFlinger,并调用AudioHandler的persistVolume方法将音量的设置信息存储到SettingsProvider中

调用sendVolumeUpdate()方法,显示音量调节通知框 此方法通过AIDL最终调用SystemUI中VolumeDialogController的onVolumeChangedW方法去显示音量调节通知框.

发布了41 篇原创文章 · 获赞 35 · 访问量 4345

猜你喜欢

转载自blog.csdn.net/weixin_38140931/article/details/88292548