今天跟了一下Android系统按键静音的流程,Android实现了在系统层面静音。输出给底层的音量为0。

按键使用注入按键方式实现,静音按键值:

public static final int KEYCODE_VOLUME_MUTE     = 164;

注入方式:

KeyEvent k = new KeyEvent(KeyEvent.ACTION_DOWN,KeyEvent.KEYCODE_VOLUME_MUTE);InputManager.getInstance().injectInputEvent(key, 0);

或者:

simulateKey(KeyEvent.KEYCODE_VOLUME_MUTE);public static void simulateKey(final int KeyCode) {    new Thread() {        @Override        public void run() {            try {                Instrumentation inst = new Instrumentation();                inst.sendKeyDownUpSync(KeyCode);            } catch (Exception e) {                Log.e("hello", e.toString());            }        }    }.start();}

调用流程:
DecorView.java --> PhoneWindow.java --> MediaSessionService.java

窗口监听Key消息的过程省略过,在Input输入系统中已经分析过。

\frameworks\base\services\core\java\com\android\server\media\MediaSessionService.java
dispatchVolumeKeyEvent()
dispatchVolumeKeyEventLocked()

\frameworks\base\services\core\java\com\android\server\audio\AudioService.java
adjustSuggestedStreamVolume()

private void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,            String callingPackage, String caller, int uid) {                    //省略一部分代码        //...// mute为true        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);}protected void adjustStreamVolume(int streamType, int direction, int flags,            String callingPackage, String caller, int uid) {                    //省略一部分代码        //...    //省略一部分代码    //...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);                        }                    }                }            }            //省略一部分代码    //...            //省略一部分代码        //...}

通过调用 mStreamStates[stream].mute(state);来做stream mute.

        public void mute(boolean state) {            boolean changed = false;            synchronized (VolumeStreamState.class) {                if (state != mIsMuted) {                    changed = true;                    mIsMuted = state;                    // Set the new mute volume. This propagates the values to                    // the audio system, otherwise the volume won't be changed                    // at the lower level.                    sendMsg(mAudioHandler,                            MSG_SET_ALL_VOLUMES,                            SENDMSG_QUEUE,                            0,                            0,                            this, 0);                }            }            if (changed) {                // Stream mute changed, fire the intent.                Intent intent = new Intent(AudioManager.STREAM_MUTE_CHANGED_ACTION);                intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, mStreamType);                intent.putExtra(AudioManager.EXTRA_STREAM_VOLUME_MUTED, state);                sendBroadcastToAll(intent);            }        }

通过发送MSG_SET_ALL_VOLUMES消息,告知Audio System处理音量,降到最低。

        @Override        public void handleMessage(Message msg) {            switch (msg.what) {                case MSG_SET_DEVICE_VOLUME:                    setDeviceVolume((VolumeStreamState) msg.obj, msg.arg1);                    break;                case MSG_SET_ALL_VOLUMES:                    setAllVolumes((VolumeStreamState) msg.obj);                    break;        }                private void setAllVolumes(VolumeStreamState streamState) {            // Apply volume            streamState.applyAllVolumes();            // Apply change to all streams using this one as alias            int numStreamTypes = AudioSystem.getNumStreamTypes();            for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {                if (streamType != streamState.mStreamType &&                        mStreamVolumeAlias[streamType] == streamState.mStreamType) {                    mStreamStates[streamType].applyAllVolumes();                }            }        }        public void applyAllVolumes() {            synchronized (VolumeStreamState.class) {                // apply device specific volumes first                int index;                for (int i = 0; i < mIndexMap.size(); i++) {                    final int device = mIndexMap.keyAt(i);                    if (device != AudioSystem.DEVICE_OUT_DEFAULT) {                        if (mIsMuted) {                            index = 0;                        } else if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&                                mAvrcpAbsVolSupported) {                            index = getAbsoluteVolumeIndex((getIndex(device) + 5)/10);                        } else if ((device & mFullVolumeDevices) != 0) {                            index = (mIndexMax + 5)/10;                        } else if ((device & AudioSystem.DEVICE_OUT_HEARING_AID) != 0) {                            index = (mIndexMax + 5)/10;                        } else {                            //index = (mIndexMap.valueAt(i) + 5)/10;                            index = (mIndexMax+5)/10;//fixed system volume(zhuqiang2019.1.2)                        }                        AudioSystem.setStreamVolumeIndex(mStreamType, index, device);                    }                }                // apply default volume last: by convention , default device volume will be used                // by audio policy manager if no explicit volume is present for a given device type                if (mIsMuted) {                    index = 0;                } else {                    index = (getIndex(AudioSystem.DEVICE_OUT_DEFAULT) + 5)/10;                }                if(mUseFixedVolume)                {                    index = (mIndexMax+5)/10;//fixed system volume(zhuqiang2019.1.2)                }                AudioSystem.setStreamVolumeIndex(                        mStreamType, index, AudioSystem.DEVICE_OUT_DEFAULT);            }        }

关键代码:AudioSystem.setStreamVolumeIndex( mStreamType, index, AudioSystem.DEVICE_OUT_DEFAULT);

\frameworks\av\media\libaudioclient\AudioSystem.cpp

status_t AudioSystem::setStreamVolumeIndex(audio_stream_type_t stream,                                           int index,                                           audio_devices_t device){    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();    if (aps == 0) return PERMISSION_DENIED;    return aps->setStreamVolumeIndex(stream, index, device);}

frameworks\av\services\audiopolicy\managerdefault\AudioPolicyManager.cpp

status_t AudioPolicyManager::setStreamVolumeIndex(audio_stream_type_t stream,                                                  int index,                                                  audio_devices_t device){    // VOICE_CALL stream has minVolumeIndex > 0  but can be muted directly by an    // app that has MODIFY_PHONE_STATE permission.    if (((index < mVolumeCurves->getVolumeIndexMin(stream)) &&            !(stream == AUDIO_STREAM_VOICE_CALL && index == 0)) ||            (index > mVolumeCurves->getVolumeIndexMax(stream))) {        return BAD_VALUE;    }    if (!audio_is_output_device(device)) {        return BAD_VALUE;    }    // Force max volume if stream cannot be muted    if (!mVolumeCurves->canBeMuted(stream)) index = mVolumeCurves->getVolumeIndexMax(stream);    ALOGV("setStreamVolumeIndex() stream %d, device %08x, index %d",          stream, device, index);    // update other private stream volumes which follow this one    for (int curStream = 0; curStream < AUDIO_STREAM_FOR_POLICY_CNT; curStream++) {        if (!streamsMatchForvolume(stream, (audio_stream_type_t)curStream)) {            continue;        }        mVolumeCurves->addCurrentVolumeIndex((audio_stream_type_t)curStream, device, index);    }    // update volume on all outputs and streams matching the following:    // - The requested stream (or a stream matching for volume control) is active on the output    // - The device (or devices) selected by the strategy corresponding to this stream includes    // the requested device    // - For non default requested device, currently selected device on the output is either the    // requested device or one of the devices selected by the strategy    // - For default requested device (AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME), apply volume only if    // no specific device volume value exists for currently selected device.    status_t status = NO_ERROR;    for (size_t i = 0; i < mOutputs.size(); i++) {        sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);        audio_devices_t curDevice = Volume::getDeviceForVolume(desc->device());        for (int curStream = 0; curStream < AUDIO_STREAM_FOR_POLICY_CNT; curStream++) {            if (!streamsMatchForvolume(stream, (audio_stream_type_t)curStream)) {                continue;            }            if (!(desc->isStreamActive((audio_stream_type_t)curStream) ||                    (isInCall() && (curStream == AUDIO_STREAM_VOICE_CALL)))) {                continue;            }            routing_strategy curStrategy = getStrategy((audio_stream_type_t)curStream);            audio_devices_t curStreamDevice = Volume::getDeviceForVolume(getDeviceForStrategy(                    curStrategy, false /*fromCache*/));            if ((device != AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME) &&                    ((curStreamDevice & device) == 0)) {                continue;            }            bool applyVolume;            if (device != AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME) {                curStreamDevice |= device;                applyVolume = (curDevice & curStreamDevice) != 0;            } else {                applyVolume = !mVolumeCurves->hasVolumeIndexForDevice(                        stream, curStreamDevice);            }            if (applyVolume) {                //FIXME: workaround for truncated touch sounds                // delayed volume change for system stream to be removed when the problem is                // handled by system UI                status_t volStatus =                        checkAndSetVolume((audio_stream_type_t)curStream, index, desc, curDevice,                            (stream == AUDIO_STREAM_SYSTEM) ? TOUCH_SOUND_FIXED_DELAY_MS : 0);                if (volStatus != NO_ERROR) {                    status = volStatus;                }            }        }    }    return status;}status_t AudioPolicyManager::checkAndSetVolume(audio_stream_type_t stream,                                                   int index,                                                   const sp<AudioOutputDescriptor>& outputDesc,                                                   audio_devices_t device,                                                   int delayMs,                                                   bool force){    // do not change actual stream volume if the stream is muted    if (outputDesc->mMuteCount[stream] != 0) {        ALOGVV("checkAndSetVolume() stream %d muted count %d",              stream, outputDesc->mMuteCount[stream]);        return NO_ERROR;    }    audio_policy_forced_cfg_t forceUseForComm =            mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_COMMUNICATION);    // do not change in call volume if bluetooth is connected and vice versa    if ((stream == AUDIO_STREAM_VOICE_CALL && forceUseForComm == AUDIO_POLICY_FORCE_BT_SCO) ||        (stream == AUDIO_STREAM_BLUETOOTH_SCO && forceUseForComm != AUDIO_POLICY_FORCE_BT_SCO)) {        ALOGV("checkAndSetVolume() cannot set stream %d volume with force use = %d for comm",             stream, forceUseForComm);        return INVALID_OPERATION;    }    if (device == AUDIO_DEVICE_NONE) {        device = outputDesc->device();    }    float volumeDb = computeVolume(stream, index, device);    if (outputDesc->isFixedVolume(device) ||            // Force VoIP volume to max for bluetooth SCO            ((stream == AUDIO_STREAM_VOICE_CALL || stream == AUDIO_STREAM_BLUETOOTH_SCO) &&             (device & AUDIO_DEVICE_OUT_ALL_SCO) != 0)) {        volumeDb = 0.0f;    }    outputDesc->setVolume(volumeDb, stream, device, delayMs, force);    if (stream == AUDIO_STREAM_VOICE_CALL ||        stream == AUDIO_STREAM_BLUETOOTH_SCO) {        float voiceVolume;        // Force voice volume to max for bluetooth SCO as volume is managed by the headset        if (stream == AUDIO_STREAM_VOICE_CALL) {            voiceVolume = (float)index/(float)mVolumeCurves->getVolumeIndexMax(stream);        } else {            voiceVolume = 1.0;        }        if (voiceVolume != mLastVoiceVolume) {            mpClientInterface->setVoiceVolume(voiceVolume, delayMs);            mLastVoiceVolume = voiceVolume;        }    }    return NO_ERROR;}

打印:
2020-06-13 16:17:18.136 2523-4902/? V/APM::AudioOutputDescriptor: setVolume() for stream 3, volume -758.000000, delay 0
2020-06-13 16:17:26.360 2523-2684/? V/APM::AudioOutputDescriptor: setVolume() for stream 3, volume 0.000000, delay 0
2020-06-13 16:17:28.369 2523-2684/? V/APM::AudioOutputDescriptor: setVolume() for stream 3, volume -758.000000, delay 0

Mute时,volume 为-758.000000

更多相关文章

  1. TextView过长显示省略号, TextView文字中间加横线
  2. android 透明效果
  3. Android(安卓)Edittext设置负数以及小数
  4. 几款好用的Android(安卓)Studio插件
  5. TextView添加ClickableSpan和LinkMovementMethod之间的关系
  6. android中的提示信息显示方法(toast应用)
  7. Android实现widget定时更新
  8. Android(安卓)中使用OpenGL ES进行2D开发(GLSurfaceView)
  9. Android应用实例之----基于Service与ContentProvider的音乐播放

随机推荐

  1. Android——编译odex保护
  2. android隐藏IME(输入法)输入框
  3. Android下拉刷新和上拉加载更多
  4. 安卓常用属性
  5. Android解析XML文件的三种方式
  6. android:windowSoftInputMode属性使用
  7. 调用Android系统设置中的Intent
  8. android 时区转换
  9. Android中fragment A里面点击button跳转
  10. android ndk 调用第三方so