Android Framework Audio Subsystem (14) Processus de réglage du volume des touches de volume

Cette série d'articles lien Master: sous-répertoire thématique cadre Android classe Sous - système audio


Résumé et description des points clés de ce chapitre:

Ce chapitre se concentre principalement sur la partie de traitement des touches de volume de l'analyse de processus dans le réglage du volume en haut à gauche de la carte mentale ci-dessus. Principalement analysé, le flux de traitement des clés de volume est principalement divisé en 3 parties:

  1. Traitement du sous-système d'entrée au sous-système audio (jusqu'à AudioService.adjustSuggestedStreamVolume)
  2. Flux de traitement audio (de l'analyse à partir de AudioService.adjustSuggestedStreamVolume jusqu'à l'envoi de MSG_SET_DEVICE_VOLUME à mAudioHandler pour traitement.)
  3. Message de processus MSG_SET_DEVICE_VOLUME

1 Traitement du sous-système d'entrée au sous-système audio (jusqu'à AudioService.adjustSuggestedStreamVolume)

Sur la base du sous-système d'entrée et de sortie, nous avons commencé à analyser le traitement des clés. Les clés passeront de getEvent de inputReader à inputDisptacher à la méthode ViewPostImeInputStage :: processKeyEvent dans ViewRootimpl (reportez-vous au sous-système d'entrée du répertoire du sous-système Android dans le catalogue de rubriques spéciales ici ), Le code processKeyEvent est le suivant:

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

Ici mFallbackEventHandler <= equivalence => PhoneFallbackEventHandler, c'est-à-dire que le traitement des clés de volume sera transféré à PhoneFallbackEventHandler, et son code dispatchKeyEvent est implémenté comme suit:

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

L'implémentation du code de onKeyDown et onKeyUp est la suivante:

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

La méthode sendVolumeKeyEvent de MediaSessionLegacyHelper sera appelée ici. L'implémentation du code est la suivante:

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

Continuez d'analyser l'implémentation de mSessionManager.dispatchAdjustVolume ici, le code est le suivant:

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

Le service ici est de type SessionManagerImpl et le code dispatchAdjustVolume correspondant est implémenté comme suit:

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

Continuez d'analyser dispatchAdjustVolumeLocked, l'implémentation du code est la suivante:

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

Enfin, AudioService.adjustSuggestedStreamVolume est appelé ici. Du sous-système d'entrée au sous-système audio.


2 Flux de traitement audio (de AudioService.adjustSuggestedStreamVolume à l'envoi du 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);
}

Analyse de getActiveStreamType, l'implémentation du code est la suivante:

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

Analyse de adjustStreamVolume, l'implémentation du code est la suivante:

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

Après une série de traitements, cela a finalement envoyé MSG_SET_DEVICE_VOLUME à mAudioHandler pour traitement.


3 Traitez le message MSG_SET_DEVICE_VOLUME

Ici commence à analyser le processus de traitement du message MSG_SET_DEVICE_VOLUME mAudioHandler handleMessage Le traitement est le suivant:

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

Continuez d'analyser l'implémentation de setDeviceVolume ici, le code est le suivant:

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

Ici, le code applyDeviceVolume_syncVSS est implémenté comme suit:

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

Ici, continuez d'analyser l'implémentation de setStreamVolumeIndex, setStreamVolumeIndex est une fonction JNI, la relation de mappage est:

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

La méthode mappée est android_media_AudioSystem_setStreamVolumeIndex, le code est le suivant:

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

Continuez d'analyser l'implémentation de AudioSystem :: setStreamVolumeIndex ici, le code est le suivant:

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

La méthode setStreamVolumeIndex de AudioPolicyManager est appelée ici. L'implémentation du code est la suivante:

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

La méthode checkAndSetVolume est appelée ici et le code est implémenté comme suit:

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

Ici, la méthode setStreamVolume (la méthode de AudioPolicyClient sera appelée éventuellement, et l'implémentation du code est la suivante:

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

La méthode setStreamVolume d'AudioPolicyService est appelée ici et le code est implémenté comme suit:

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

Ici, le code du volumeCommand d'AudioCommandThread est implémenté comme suit

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

Faites attention à l'implémentation de sendCommand, le code est le suivant:

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

Ici, le thread correspondant à AudioCommandThread est réveillé. Regardez son implémentation de threadloop. Le code est le suivant:

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

Après avoir réveillé le thread, la méthode setStreamVolume d'AudioSystem est appelée ici. L'implémentation du code est la suivante:

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

appeler ici pour setStreamVolume AudioFlinger, dans ce processus d'analyse base Cadre Android pour régler le volume du sous - système audio (13) ont analysé


4 Processus sommaire

Rapport du bas de la clé de volume au sous-système d'entrée, puis du sous-système d'entrée au sous-système audio, qui est traité par le sous-système audio: En général, si l'APP ne réécrit pas sa fonction de traitement, le traitement de la clé de volume sera transféré à PhoneFallbackEventHandler Pour faire face, à ce moment AudioService.adjustSuggestedStreamVolume sera ajusté pour ajuster le volume du "flux recommandé", le processus de base est le suivant:

  1. Obtenez le "flux recommandé": stream = getActiveStreamType (...)
  2. Définir le volume du "flux recommandé": définissez le volume des autres flux appartenant au même alias. Pour différents appareils (téléphone, TV, tablette), mStreamVolumeAlias ​​pointe vers des tableaux différents
  3. Réglez le volume du flux: définissez le tableau dans audioflinger et PlaybackThread: mStreamTypes [stream] .volume = value;

  

 

 

Publié 291 articles originaux · loué 47 · 30 000+ vues

Je suppose que tu aimes

Origine blog.csdn.net/vviccc/article/details/105452442
conseillé
Classement