Android Framework Audio Subsystem (14) Volume key volume adjustment process

This series of articles Master link: Thematic sub-directory Android Framework Class Audio Subsystem


Summary and description of key points in this chapter:

This chapter mainly focuses on the volume key processing part of the process analysis in the upper left volume adjustment of the mind map above. Mainly analyzed the volume key processing flow is mainly divided into 3 parts:

  1. Processing from input subsystem to audio subsystem (until AudioService.adjustSuggestedStreamVolume)
  2. Audio processing flow (from the analysis starting from AudioService.adjustSuggestedStreamVolume to sending MSG_SET_DEVICE_VOLUME to mAudioHandler for processing.)
  3. Process message MSG_SET_DEVICE_VOLUME

1 Processing from input subsystem to audio subsystem (until AudioService.adjustSuggestedStreamVolume)

On the basis of the input and output subsystem, we began to analyze the processing of the keys. The keys will go from the getEvent of inputReader to the inputDisptacher to the ViewPostImeInputStage :: processKeyEvent method in ViewRootimpl (refer to the Android Subsystem Directory Input Subsystem in the special topic catalog here ), The processKeyEvent code here is as follows:

private int processKeyEvent(QueuedInputEvent q) {
    final KeyEvent event = (KeyEvent)q.mEvent;
    //...
    // Apply the fallback event policy.
    if (mFallbackEventHandler.dispatchKeyEvent(event)) {
        return FINISH_HANDLED;
    }
    //...
    // Handle automatic focus changes...
    //...
    return FORWARD;
}

Here mFallbackEventHandler <= equivalent => PhoneFallbackEventHandler, that is, the processing of the volume key will be handed over to PhoneFallbackEventHandler, and its dispatchKeyEvent code is implemented as follows:

public boolean dispatchKeyEvent(KeyEvent event) {

    final int action = event.getAction();
    final int keyCode = event.getKeyCode();

    if (action == KeyEvent.ACTION_DOWN) {
        return onKeyDown(keyCode, event);
    } else {
        return onKeyUp(keyCode, event);
    }
}

The code implementation of onKeyDown and onKeyUp is as follows:

boolean onKeyDown(int keyCode, KeyEvent event) {
    final KeyEvent.DispatcherState dispatcher = mView.getKeyDispatcherState();
    switch (keyCode) {
        case KeyEvent.KEYCODE_VOLUME_UP:
        case KeyEvent.KEYCODE_VOLUME_DOWN:
        case KeyEvent.KEYCODE_VOLUME_MUTE: {
            MediaSessionLegacyHelper.getHelper(mContext).sendVolumeKeyEvent(event, false);
            return true;
        }
        //...
    }
    //...
}

boolean onKeyUp(int keyCode, KeyEvent event) {
    final KeyEvent.DispatcherState dispatcher = mView.getKeyDispatcherState();
    if (dispatcher != null) {
        dispatcher.handleUpEvent(event);
    }

    switch (keyCode) {
        case KeyEvent.KEYCODE_VOLUME_UP:
        case KeyEvent.KEYCODE_VOLUME_DOWN:
        case KeyEvent.KEYCODE_VOLUME_MUTE: {
            if (!event.isCanceled()) {
                //MediaSessionLegacyHelper.getHelper(mContext)<=等价=>MediaSessionLegacyHelper
                MediaSessionLegacyHelper.getHelper(mContext).sendVolumeKeyEvent(event, false);
            }
            return true;
        }
        //...
    }
    //...
}

The sendVolumeKeyEvent method of MediaSessionLegacyHelper will be called here. The code implementation is as follows:

public void sendVolumeKeyEvent(KeyEvent keyEvent, boolean musicOnly) {
    //...
    if (down || up) {
        //...
        if (direction != 0) {
            // If this is action up we want to send a beep for non-music events
            if (up) {
                direction = 0;
            }
            mSessionManager.dispatchAdjustVolume(AudioManager.USE_DEFAULT_STREAM_TYPE,
                    direction, flags);
        } else if (isMute) {
            if (down) {
                mSessionManager.dispatchAdjustVolume(AudioManager.USE_DEFAULT_STREAM_TYPE,
                        MediaSessionManager.DIRECTION_MUTE, flags);
            }
            mSessionManager.dispatchAdjustVolume(AudioManager.USE_DEFAULT_STREAM_TYPE,
                    0 /* direction, causes UI to show on down */, flags);
        }
    }
}

Continue to analyze the implementation of mSessionManager.dispatchAdjustVolume here, the code is as follows:

public void dispatchAdjustVolume(int suggestedStream, int direction, int flags) {
    try {
        mService.dispatchAdjustVolume(suggestedStream, direction, flags);
    } catch (RemoteException e) {
        Log.e(TAG, "Failed to send adjust volume.", e);
    }
}

The service here is of type SessionManagerImpl, and the corresponding dispatchAdjustVolume code is implemented as follows:

public void dispatchAdjustVolume(int suggestedStream, int delta, int flags) {
    final int pid = Binder.getCallingPid();
    final int uid = Binder.getCallingUid();
    final long token = Binder.clearCallingIdentity();
    try {
        synchronized (mLock) {
            MediaSessionRecord session = mPriorityStack
                    .getDefaultVolumeSession(mCurrentUserId);
            dispatchAdjustVolumeLocked(suggestedStream, delta, flags, session);
        }
    } finally {
        Binder.restoreCallingIdentity(token);
    }
}

Continue to analyze dispatchAdjustVolumeLocked, the code implementation is as follows:

private void dispatchAdjustVolumeLocked(int suggestedStream, int direction, int flags,
        MediaSessionRecord session) {
    boolean preferSuggestedStream = false;
    if (isValidLocalStreamType(suggestedStream)
            && AudioSystem.isStreamActive(suggestedStream, 0)) {
        preferSuggestedStream = true;
    }
    if (session == null || preferSuggestedStream) {
        if ((flags & AudioManager.FLAG_ACTIVE_MEDIA_ONLY) != 0
                && !AudioSystem.isStreamActive(AudioManager.STREAM_MUSIC, 0)) {
            return;
        }
        try {
            String packageName = getContext().getOpPackageName();
            if (mUseMasterVolume) {
                boolean isMasterMute = mAudioService.isMasterMute();
                if (direction == MediaSessionManager.DIRECTION_MUTE) {
                    mAudioService.setMasterMute(!isMasterMute, flags, packageName, mICallback);
                } else {
                    mAudioService.adjustMasterVolume(direction, flags, packageName);
                    if (isMasterMute && direction != 0) {
                        mAudioService.setMasterMute(false, flags, packageName, mICallback);
                    }
                }
            } else {
                boolean isStreamMute = mAudioService.isStreamMute(suggestedStream);
                if (direction == MediaSessionManager.DIRECTION_MUTE) {
                    mAudioManager.setStreamMute(suggestedStream, !isStreamMute);
                } else {
                    mAudioService.adjustSuggestedStreamVolume(direction, suggestedStream,
                            flags, packageName);
                    // Do not call setStreamMute when direction = 0 which is used just to
                    // show the UI.
                    if (isStreamMute && direction != 0) {
                        mAudioManager.setStreamMute(suggestedStream, false);
                    }
                }
            }
        } catch (RemoteException e) {
            Log.e(TAG, "Error adjusting default volume.", e);
        }
    } else {
        session.adjustVolume(direction, flags, getContext().getPackageName(),
                UserHandle.myUserId(), true);
    }
}

Finally, AudioService.adjustSuggestedStreamVolume is called here. From the input subsystem to the audio subsystem.


2 Audio processing flow (from AudioService.adjustSuggestedStreamVolume to sending message MSG_SET_DEVICE_VOLUME)

private void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
        String callingPackage, int uid) {
    int streamType;
    if (mVolumeControlStream != -1) {
        streamType = mVolumeControlStream;
    } else {
        //关键点1:获取推荐的streamType,这里根据建议的流类型与AudioService的实际情况,返回一个值
        streamType = getActiveStreamType(suggestedStreamType);
    }
    //...
    //关键点2
    adjustStreamVolume(streamType, direction, flags, callingPackage, uid);
}

Analysis of getActiveStreamType, the code implementation is as follows:

private int getActiveStreamType(int suggestedStreamType) {
    switch (mPlatformType) {
    case PLATFORM_VOICE://针对Phone
        if (isInCommunication()) {
            //通话中,如果用蓝牙耳机就设置STREAM_BLUETOOTH_SCO,否则设置STREAM_VOICE_CALL
            if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
                    == AudioSystem.FORCE_BT_SCO) {
                return AudioSystem.STREAM_BLUETOOTH_SCO;
            } else {
                return AudioSystem.STREAM_VOICE_CALL;
            }
        } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
            if (isAfMusicActiveRecently(StreamOverride.sDelayMs)) {
                return AudioSystem.STREAM_MUSIC;
                } else :
                    return AudioSystem.STREAM_RING;
            }
        } else if (isAfMusicActiveRecently(0)) {
            return AudioSystem.STREAM_MUSIC;
        }
        break;
    case PLATFORM_TELEVISION://电视
        if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
                // TV always defaults to STREAM_MUSIC
                return AudioSystem.STREAM_MUSIC;
        }
        break;
    default://平板或者其他设备。
        if (isInCommunication()) {
            if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
                    == AudioSystem.FORCE_BT_SCO) {
                return AudioSystem.STREAM_BLUETOOTH_SCO;
            } else {
                return AudioSystem.STREAM_VOICE_CALL;
            }
        } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_NOTIFICATION,
                StreamOverride.sDelayMs) ||
                AudioSystem.isStreamActive(AudioSystem.STREAM_RING,
                        StreamOverride.sDelayMs)) {
            return AudioSystem.STREAM_NOTIFICATION;
        } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
            if (isAfMusicActiveRecently(StreamOverride.sDelayMs)) {
                return AudioSystem.STREAM_MUSIC;
            } else {
                return AudioSystem.STREAM_NOTIFICATION;
            }
        }
        break;
    }
    return suggestedStreamType;
}

Analysis of adjustStreamVolume, the code implementation is as follows:

private void adjustStreamVolume(int streamType, int direction, int flags,
        String callingPackage, int uid) {
    //...
    ensureValidDirection(direction);//确认 调整的音量方向
    ensureValidStreamType(streamType);//确认 调整的stream类型  
    
    int streamTypeAlias = mStreamVolumeAlias[streamType];
    //VolumeStreamState类,保存与一个流类型所有音量相关的信息
    VolumeStreamState streamState = mStreamStates[streamTypeAlias];
    final int device = getDeviceForStream(streamTypeAlias);
    //...
    flags &= ~AudioManager.FLAG_FIXED_VOLUME;
    if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
           ((device & mFixedVolumeDevices) != 0)) {
        flags |= AudioManager.FLAG_FIXED_VOLUME;
        if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
                (device & mSafeMediaVolumeDevices) != 0) {
            step = mSafeMediaVolumeIndex;
        } else {
            step = streamState.getMaxIndex();
        }
        if (aliasIndex != 0) {
            aliasIndex = step;
        }
    } else {
        // convert one UI step (+/-1) into a number of internal units on the stream alias
        //这里将音量值的变化量从源 stream类型变换到目标stream类型,
        //由于不同的流类型的音量调节范围不同,所以这个转换是必需的
        step = rescaleIndex(10, streamType, streamTypeAlias);
    }

    if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
            (streamTypeAlias == getMasterStreamType())) {
        int ringerMode = getRingerModeInternal();
        if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) {
            flags &= ~AudioManager.FLAG_VIBRATE;
        }
        final int result = checkForRingerModeChange(aliasIndex, direction, step);
        //布尔变量,用来表示是否有必要继续设置音量值
        adjustVolume = (result & FLAG_ADJUST_VOLUME) != 0;
        if ((result & AudioManager.FLAG_SHOW_SILENT_HINT) != 0) {
            flags |= AudioManager.FLAG_SHOW_SILENT_HINT;
        }
        if ((result & AudioManager.FLAG_SHOW_VIBRATE_HINT) != 0) {
            flags |= AudioManager.FLAG_SHOW_VIBRATE_HINT;
        }
    }
    //取出调整前的音量值。这个值会在sendVolumeUpdate()调用
    int oldIndex = mStreamStates[streamType].getIndex(device);

    if (adjustVolume && (direction != AudioManager.ADJUST_SAME)) {
        //...
        /*判断streamState.adjustIndex 返回值,如果音量值在调整之后并没有发生变化
         *比如到了最大值,就不需要继续后面的操作了
         */
        if ((direction == AudioManager.ADJUST_RAISE) &&
                !checkSafeMediaVolume(streamTypeAlias, aliasIndex + step, device)) {
            mVolumeController.postDisplaySafeVolumeWarning(flags);
        } else if (streamState.adjustIndex(direction * step, device)) {
            //通过sendMsg()发送消息MSG_SET_DEVICE_VOLUME到mAudioHandler
            sendMsg(mAudioHandler,
                    MSG_SET_DEVICE_VOLUME,
                    SENDMSG_QUEUE,
                    device,
                    0,
                    streamState,
                    0);
        }
        //...
    }
    //...
    int index = mStreamStates[streamType].getIndex(device);
    //通知外界音量值发生了变化
    sendVolumeUpdate(streamType, oldIndex, index, flags);
}

After a series of processing, this finally sent MSG_SET_DEVICE_VOLUME to mAudioHandler for processing.


3 Process the message MSG_SET_DEVICE_VOLUME

Here begins to analyze the process of processing the message MSG_SET_DEVICE_VOLUME mAudioHandler handleMessage processing is as follows:

@Override
public void handleMessage(Message msg) {
    switch (msg.what) {

        case MSG_SET_DEVICE_VOLUME:
            setDeviceVolume((VolumeStreamState) msg.obj, msg.arg1);
            break;
		//...
        case MSG_PERSIST_MICROPHONE_MUTE:
            Settings.System.putIntForUser(mContentResolver,
                                         Settings.System.MICROPHONE_MUTE,
                                         msg.arg1,
                                         msg.arg2);
            break;
    }
}

Continue to analyze the implementation of setDeviceVolume here, the code is as follows:

private void setDeviceVolume(VolumeStreamState streamState, int device) {

    synchronized (VolumeStreamState.class) {
        // Apply volume
        streamState.applyDeviceVolume_syncVSS(device);

        // 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) {
                int streamDevice = getDeviceForStream(streamType);
                if ((device != streamDevice) && mAvrcpAbsVolSupported &&
                        ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0)) {
                    mStreamStates[streamType].applyDeviceVolume_syncVSS(device);
                }
                mStreamStates[streamType].applyDeviceVolume_syncVSS(streamDevice);
            }
        }
    }
    //...
}

Here the applyDeviceVolume_syncVSS code is implemented as follows:

// must be called while synchronized VolumeStreamState.class
public void applyDeviceVolume_syncVSS(int device) {
    int index;
    if (isMuted_syncVSS()) {
        index = 0;
    } else if (((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 && mAvrcpAbsVolSupported)
            || ((device & mFullVolumeDevices) != 0)) {
        index = (mIndexMax + 5)/10;
    } else {
        index = (getIndex(device) + 5)/10;
    }
    AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
}

Here continue to analyze the implementation of setStreamVolumeIndex, setStreamVolumeIndex is a JNI function, the mapping relationship is:

    {"setStreamVolumeIndex","(III)I",   (void *)android_media_AudioSystem_setStreamVolumeIndex},

The mapped method is android_media_AudioSystem_setStreamVolumeIndex, the code is as follows:

static jint
android_media_AudioSystem_setStreamVolumeIndex(JNIEnv *env,
                                               jobject thiz,
                                               jint stream,
                                               jint index,
                                               jint device)
{
    return (jint) check_AudioSystem_Command(
            AudioSystem::setStreamVolumeIndex(static_cast <audio_stream_type_t>(stream),
                                              index,
                                              (audio_devices_t)device));
}

Continue to analyze the implementation of AudioSystem :: setStreamVolumeIndex here, the code is as follows:

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

The setStreamVolumeIndex method of AudioPolicyManager is called here. The code implementation is as follows:

status_t AudioPolicyManager::setStreamVolumeIndex(audio_stream_type_t stream,
                                                      int index,
                                                      audio_devices_t device)
{
    //...
    // Force max volume if stream cannot be muted
    if (!mStreams[stream].mCanBeMuted) index = mStreams[stream].mIndexMax;
    if (device == AUDIO_DEVICE_OUT_DEFAULT) {
        mStreams[stream].mIndexCur.clear();
    }
    mStreams[stream].mIndexCur.add(device, index);

    // update volume on all outputs whose current device is also selected by the same
    // strategy as the device specified by the caller
    audio_devices_t strategyDevice = getDeviceForStrategy(getStrategy(stream), true /*fromCache*/);


    //FIXME: AUDIO_STREAM_ACCESSIBILITY volume follows AUDIO_STREAM_MUSIC for now
    audio_devices_t accessibilityDevice = AUDIO_DEVICE_NONE;
    if (stream == AUDIO_STREAM_MUSIC) {
        mStreams[AUDIO_STREAM_ACCESSIBILITY].mIndexCur.add(device, index);
        accessibilityDevice = getDeviceForStrategy(STRATEGY_ACCESSIBILITY, true /*fromCache*/);
    }
    if ((device != AUDIO_DEVICE_OUT_DEFAULT) &&
            (device & (strategyDevice | accessibilityDevice)) == 0) {
        return NO_ERROR;
    }
    status_t status = NO_ERROR;
    for (size_t i = 0; i < mOutputs.size(); i++) {
        audio_devices_t curDevice =
                getDeviceForVolume(mOutputs.valueAt(i)->device());
        if ((device == AUDIO_DEVICE_OUT_DEFAULT) || ((curDevice & strategyDevice) != 0)) {
            status_t volStatus = checkAndSetVolume(stream, index, mOutputs.keyAt(i), curDevice);
            if (volStatus != NO_ERROR) {
                status = volStatus;
            }
        }
        if ((device == AUDIO_DEVICE_OUT_DEFAULT) || ((curDevice & accessibilityDevice) != 0)) {
            status_t volStatus = checkAndSetVolume(AUDIO_STREAM_ACCESSIBILITY,
                                                   index, mOutputs.keyAt(i), curDevice);
        }
    }
    return status;
}

The checkAndSetVolume method is called here, and the code is implemented as follows:

status_t AudioPolicyManager::checkAndSetVolume(audio_stream_type_t stream,
                                                   int index,
                                                   audio_io_handle_t output,
                                                   audio_devices_t device,
                                                   int delayMs,
                                                   bool force)
{
    //...
    // We actually change the volume if:
    // - the float value returned by computeVolume() changed
    // - the force flag is set
    if (volume != mOutputs.valueFor(output)->mCurVolume[stream] ||
            force) {
        mOutputs.valueFor(output)->mCurVolume[stream] = volume;
        if (stream == AUDIO_STREAM_BLUETOOTH_SCO) {
            mpClientInterface->setStreamVolume(AUDIO_STREAM_VOICE_CALL, volume, output, delayMs);
        }
        mpClientInterface->setStreamVolume(stream, volume, output, delayMs);
    }

    if (stream == AUDIO_STREAM_VOICE_CALL ||
        stream == AUDIO_STREAM_BLUETOOTH_SCO) {
        float voiceVolume;
        if (stream == AUDIO_STREAM_VOICE_CALL) {
            voiceVolume = (float)index/(float)mStreams[stream].mIndexMax;
        } else {
            voiceVolume = 1.0;
        }

        if (voiceVolume != mLastVoiceVolume && output == mPrimaryOutput) {
            mpClientInterface->setVoiceVolume(voiceVolume, delayMs);
            mLastVoiceVolume = voiceVolume;
        }
    }

    return NO_ERROR;
}

Here, the setStreamVolume (method of AudioPolicyClient will be called eventually, and the code implementation is as follows:

status_t AudioPolicyService::AudioPolicyClient::setStreamVolume(audio_stream_type_t stream,
                     float volume, audio_io_handle_t output,
                     int delay_ms)
{
    return mAudioPolicyService->setStreamVolume(stream, volume, output,
                                               delay_ms);
}

The setStreamVolume method of AudioPolicyService is called here, and the code is implemented as follows:

int AudioPolicyService::setStreamVolume(audio_stream_type_t stream,
                                        float volume,
                                        audio_io_handle_t output,
                                        int delayMs)
{
    return (int)mAudioCommandThread->volumeCommand(stream, volume,
                                                   output, delayMs);
}

Here the code of AudioCommandThread's volumeCommand is implemented as follows

status_t AudioPolicyService::AudioCommandThread::volumeCommand(audio_stream_type_t stream,
                                                               float volume,
                                                               audio_io_handle_t output,
                                                               int delayMs)
{
    sp<AudioCommand> command = new AudioCommand();
    command->mCommand = SET_VOLUME;
    sp<VolumeData> data = new VolumeData();
    data->mStream = stream;
    data->mVolume = volume;
    data->mIO = output;
    command->mParam = data;
    command->mWaitStatus = true;
    return sendCommand(command, delayMs);
}

Pay attention to the implementation of sendCommand, the code is as follows:

status_t AudioPolicyService::AudioCommandThread::sendCommand(sp<AudioCommand>& command, int delayMs)
{
    {
        Mutex::Autolock _l(mLock);
        insertCommand_l(command, delayMs);
        mWaitWorkCV.signal();
    }
    Mutex::Autolock _l(command->mLock);
    while (command->mWaitStatus) {
        nsecs_t timeOutNs = kAudioCommandTimeoutNs + milliseconds(delayMs);
        if (command->mCond.waitRelative(command->mLock, timeOutNs) != NO_ERROR) {
            command->mStatus = TIMED_OUT;
            command->mWaitStatus = false;
        }
    }
    return command->mStatus;
}

Here the thread corresponding to AudioCommandThread is awakened. Look at its threadloop implementation. The code is as follows:

bool AudioPolicyService::AudioCommandThread::threadLoop()
{
    nsecs_t waitTime = INT64_MAX;
    mLock.lock();
    while (!exitPending())
    {
        sp<AudioPolicyService> svc;
        while (!mAudioCommands.isEmpty() && !exitPending()) {
            nsecs_t curTime = systemTime();
            // commands are sorted by increasing time stamp: execute them from index 0 and up
            if (mAudioCommands[0]->mTime <= curTime) {
                sp<AudioCommand> command = mAudioCommands[0];
                mAudioCommands.removeAt(0);
                mLastCommand = command;

                switch (command->mCommand) {
                //...
                //唤醒后开始处理SET_VOLUME命令
                case SET_VOLUME: {
                    VolumeData *data = (VolumeData *)command->mParam.get();
                    command->mStatus = AudioSystem::setStreamVolume(data->mStream,
                                                                    data->mVolume,
                                                                    data->mIO);
                    }break;
                //...
                default:
                    ALOGW("AudioCommandThread() unknown command %d", command->mCommand);
                }
                {
                    Mutex::Autolock _l(command->mLock);
                    if (command->mWaitStatus) {
                        command->mWaitStatus = false;
                        command->mCond.signal();
                    }
                }
                waitTime = INT64_MAX;
            } else {
                waitTime = mAudioCommands[0]->mTime - curTime;
                break;
            }
        }
        mLock.unlock();
        svc.clear();
        mLock.lock();
        if (!exitPending() && mAudioCommands.isEmpty()) {
            // release delayed commands wake lock
            release_wake_lock(mName.string());
            //在这里等待,也在这里被唤醒
            mWaitWorkCV.waitRelative(mLock, waitTime);
        }
    }
    // release delayed commands wake lock before quitting
    if (!mAudioCommands.isEmpty()) {
        release_wake_lock(mName.string());
    }
    mLock.unlock();
    return false;
}

After waking up the thread, the setStreamVolume method of AudioSystem is called here. The code implementation is as follows:

status_t AudioSystem::setStreamVolume(audio_stream_type_t stream, float value,
        audio_io_handle_t output)
{
    if (uint32_t(stream) >= AUDIO_STREAM_CNT) return BAD_VALUE;
    const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
    if (af == 0) return PERMISSION_DENIED;
    af->setStreamVolume(stream, value, output);
    return NO_ERROR;
}

Here call to setStreamVolume AudioFlinger, in this analysis process Android Framework basis to adjust the volume of the audio subsystem (13) analyzed


4 Summary process

Report from the bottom of the volume key to the input subsystem, and then from the input subsystem to the audio subsystem, which is processed by the audio subsystem: In general, if the APP does not rewrite its processing function, the processing of the volume key will be handed over to PhoneFallbackEventHandler To deal with, at this time AudioService.adjustSuggestedStreamVolume will be adjusted to adjust the volume of the "recommended stream", the core process is as follows:

  1. Get "recommended stream": stream = getActiveStreamType (...)
  2. Set the volume of the "recommended stream": set the volume of other streams belonging to the same alias. For different devices (telephone, TV, tablet), mStreamVolumeAlias ​​points to different arrays
  3. Set the volume of the stream: set the array in audioflinger and PlaybackThread: mStreamTypes [stream] .volume = value;

  

 

 

Published 291 original articles · praised 47 · 30,000+ views

Guess you like

Origin blog.csdn.net/vviccc/article/details/105452442