Android音视频六:音量调节流程

1,433 阅读3分钟

音量调节JAVA层

按键调节 和 滑动条调节 整体流程区别不大,就将图和在一起了

image.png

按键调节


    protected void adjustStreamVolume(int streamType, int direction, int flags,
            String callingPackage, String caller, int uid, boolean hasModifyAudioSettings,
            int keyEventMode) {


        // lyh 检查调节方向 和 流类型
        ensureValidDirection(direction);
        ensureValidStreamType(streamType);

        // lyh 是否是关于静音的调节(滑动条触发的)
        boolean isMuteAdjust = isMuteAdjust(direction);

        if (isMuteAdjust && !isStreamAffectedByMute(streamType)) {
            return;
        }
        
        // lyh 流类型的组名
        int streamTypeAlias = mStreamVolumeAlias[streamType];
        
        // lyh 根据流类型的别名在流类型列表中找到对应的流信息
        VolumeStreamState streamState = mStreamStates[streamTypeAlias];
        
        // lyh 拿device
        final int device = getDeviceForStream(streamTypeAlias);
        
        // lyh 当前音量下标值
        int aliasIndex = streamState.getIndex(device);
        
        boolean adjustVolume = true;
        int step;
        
        // lyh 计算步长
        flags &= ~AudioManager.FLAG_FIXED_VOLUME;
        if (streamTypeAlias == AudioSystem.STREAM_MUSIC && isFixedVolumeDevice(device)) {
            flags |= AudioManager.FLAG_FIXED_VOLUME;

            if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
                    mSafeMediaVolumeDevices.contains(device)) {
                step = safeMediaVolumeIndex(device);
            } 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
            step = rescaleStep(10, streamType, streamTypeAlias);
        }


        // lyh 看起来是调节音量时能否改变ringermode状态(组别是:STREAM_SYSTEM 第二个条件成立)
        if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
                (streamTypeAlias == getUiSoundsStreamType())) {
            int ringerMode = getRingerModeInternal();

            // lyh 重要方法
            final int result = checkForRingerModeChange(aliasIndex, direction, step,
                    streamState.mIsMuted, callingPackage, flags);
            
            adjustVolume = (result & FLAG_ADJUST_VOLUME) != 0;
        }

        // lyh 音量下标值,不知道和aliasIndex有什么区别
        int oldIndex = mStreamStates[streamType].getIndex(device);

        // lyh 第一次点击 direction = 0 ,第二次 = 1
        if (adjustVolume
                && (direction != AudioManager.ADJUST_SAME) && (keyEventMode != VOL_ADJUST_END)) {
            mAudioHandler.removeMessages(MSG_UNMUTE_STREAM);

            // lyh 滑动条的,设置同一组下的音量状态
            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)) {
                // lyh 安全音量提示
                mVolumeController.postDisplaySafeVolumeWarning(flags);
            } else if (!isFullVolumeDevice(device)
                    && (streamState.adjustIndex(direction * step, device, caller,
                            hasModifyAudioSettings)
                            || streamState.mIsMuted)) {
            
                if (streamState.mIsMuted) {
                    if (direction == AudioManager.ADJUST_RAISE) {
                        streamState.mute(false);
                    } else if (direction == AudioManager.ADJUST_LOWER) {
                        if (mIsSingleVolume) {
                            sendMsg(mAudioHandler, MSG_UNMUTE_STREAM, SENDMSG_QUEUE,
                                    streamTypeAlias, flags, null, UNMUTE_STREAM_DELAY);
                        }
                    }
                }
                
                // lyh 发送Handler消息
                sendMsg(mAudioHandler,
                        MSG_SET_DEVICE_VOLUME,
                        SENDMSG_QUEUE,
                        device,
                        0,
                        streamState,
                        0);
            }
            
        }
        
        // lyh 调整后的音量新下标
        final int newIndex = mStreamStates[streamType].getIndex(device);

        // lyh HDMI 相关
        if (adjustVolume) {
            synchronized (mHdmiClientLock) {
                if (mHdmiManager != null) {
                   ...
                }
            }
        }
        
        // lyh 更新
        sendVolumeUpdate(streamType, oldIndex, newIndex, flags, device);
    }

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

                case MSG_SET_DEVICE_VOLUME:
                    setDeviceVolume((VolumeStreamState) msg.obj, msg.arg1);
                    break;
            }
}


void setDeviceVolume(VolumeStreamState streamState, int device) {

        synchronized (VolumeStreamState.class) {
            // Apply volume
            // lyh 设置音量
            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) {
                    // Make sure volume is also maxed out on A2DP device for aliased stream
                    // that may have a different device selected
                    int streamDevice = getDeviceForStream(streamType);
                    if ((device != streamDevice) && mAvrcpAbsVolSupported
                            && AudioSystem.DEVICE_OUT_ALL_A2DP_SET.contains(device)) {
                        mStreamStates[streamType].applyDeviceVolume_syncVSS(device);
                    }
                    mStreamStates[streamType].applyDeviceVolume_syncVSS(streamDevice);
                }
            }
        }
        // Post a persist volume msg
        sendMsg(mAudioHandler,
                MSG_PERSIST_VOLUME,
                SENDMSG_QUEUE,
                device,
                0,
                streamState,
                PERSIST_DELAY);

    }


void applyDeviceVolume_syncVSS(int device) {
            int index;
            if (isFullyMuted()) {
                index = 0;
            } else if (AudioSystem.DEVICE_OUT_ALL_A2DP_SET.contains(device)
                    && mAvrcpAbsVolSupported) {
                index = getAbsoluteVolumeIndex((getIndex(device) + 5)/10);
            } else if (isFullVolumeDevice(device)) {
                index = (mIndexMax + 5)/10;
            } else if (device == AudioSystem.DEVICE_OUT_HEARING_AID) {
                index = (mIndexMax + 5)/10;
            } else {
                index = (getIndex(device) + 5)/10;
            }
            setStreamVolumeIndex(index, device);
        }




private void setStreamVolumeIndex(int index, int device) {
    // Only set audio policy BT SCO stream volume to 0 when the stream is actually muted.
    // This allows RX path muting by the audio HAL only when explicitly muted but not when
    // index is just set to 0 to repect BT requirements
    if (mStreamType == AudioSystem.STREAM_BLUETOOTH_SCO && index == 0
            && !isFullyMuted()) {
        index = 1;
    }

    int streamType = mStreamType;
    if (mStreamType >= AudioSystem.STREAM_VOICE_CALL_GS_MIN && mStreamType <= AudioSystem.STREAM_VOICE_CALL_GS_MAX) {
        streamType = AudioSystem.STREAM_VOICE_CALL;
    }
    if (DEBUG_VOL) Log.i(TAG, "setStreamVolumeIndex mStreamType " + mStreamType + ", streamType " + streamType + ", index " + index);
    AudioSystem.setStreamVolumeIndexAS(streamType, index, device);
}


滑动条调节

   private void setStreamVolume() {

  
        ensureValidStreamType(streamType);

        int streamTypeAlias = mStreamVolumeAlias[streamType];
       
        VolumeStreamState streamState = mStreamStates[streamTypeAlias];
        // lyh 拿device
        final int device = getDeviceForStream(streamType);
        int oldIndex;


        synchronized (mSafeMediaVolumeStateLock) {
            // reset any pending volume command
            mPendingVolumeCommand = null;

            oldIndex = streamState.getIndex(device);

            index = rescaleIndex(index * 10, streamType, streamTypeAlias);


            if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
                setSystemAudioVolume(oldIndex, index, getStreamMaxVolume(streamType), flags);
            }

            // lyh 检查是否安全音量
            if (!checkSafeMediaVolume(streamTypeAlias, index, device)) {
                mVolumeController.postDisplaySafeVolumeWarning(flags);
                mPendingVolumeCommand = new StreamVolumeCommand(
                                                    streamType, index, flags, device);
            } else {
                // lyh 调节音量
                onSetStreamVolume(streamType, index, flags, device, caller, hasModifyAudioSettings);
                index = mStreamStates[streamType].getIndex(device);
            }
        }

        // lyh 音量更新
        sendVolumeUpdate(streamType, oldIndex, index, flags, device);
    }

    private void onSetStreamVolume() {
        final int stream = mStreamVolumeAlias[streamType];
        // lyh
        setStreamVolumeInt(stream, index, device, false, caller, hasModifyAudioSettings);
        // setting volume on ui sounds stream type also controls silent mode
        if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
                (stream == getUiSoundsStreamType())) {
            setRingerMode(getNewRingerMode(stream, index, flags),
                    TAG + ".onSetStreamVolume", false /*external*/);
        }
  
    }


    private void setStreamVolumeInt() {

        VolumeStreamState streamState = mStreamStates[streamType];
        
        // 发送Handler消息,与按键调节流程一致了
        sendMsg(mAudioHandler,
                   MSG_SET_DEVICE_VOLUME,
                   SENDMSG_QUEUE,
                   device,
                   0,
                   streamState,
                   0);
    }


音量调节Native层

image.png

static jint
android_media_AudioSystem_setStreamVolumeIndex()
{
    return (jint) check_AudioSystem_Command(
           AudioSystem::setStreamVolumeIndex()
           );
}


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


status_t AudioPolicyManager::setStreamVolumeIndex()
{
    
    return setVolumeIndexForAttributes(attributes, index, device);
}

status_t AudioPolicyManager::setVolumeIndexForAttributes()
{

    // lyh 遍历所有设备
    for (size_t i = 0; i < mOutputs.size(); i++) {
        // lyh 设备描述符
        sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
        DeviceTypeSet curDevices = desc->devices().types();

        // lyh 检查并设置音量
        status_t volStatus = checkAndSetVolume(
                    curves, vs, index, desc, curDevices,
                    ((vs == toVolumeSource(AUDIO_STREAM_SYSTEM))?
                         TOUCH_SOUND_FIXED_DELAY_MS : 0));
   
    }
    mpClientInterface->onAudioVolumeGroupChanged(group, 0 /*flags*/);
    return status;
}


status_t AudioPolicyManager::checkAndSetVolume()
{

    // lyh 计算音量
    float volumeDb = computeVolume(curves, volumeSource, index, deviceTypes);


    // lyh 设置音量 SwAudioOutputDescriptor::setVolume
    outputDesc->setVolume(
            volumeDb, volumeSource, curves.getStreamTypes(), deviceTypes, delayMs, force);

    return NO_ERROR;
}


bool SwAudioOutputDescriptor::setVolume()
{

    for (const auto& devicePort : devices()) {
            // lyh 遍历设置音量
            for (const auto &stream : streams) {
                // lyh mClientInterface == AudioPolicyService
                mClientInterface->setStreamVolume(stream, volumeAmpl, mIoHandle, delayMs);
            }
        }
    }
    return true;
}

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


status_t AudioPolicyService::AudioCommandThread::volumeCommand()
{
    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;
    // lyh 发送指令[SET_VOLUME]去调节音量
    return sendCommand(command, delayMs);
}


status_t AudioPolicyService::AudioCommandThread::sendCommand()
{
    {
        Mutex::Autolock _l(mLock);
        insertCommand_l(command, delayMs);
        // lyh 唤醒AudioCommandThread
        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;
}


bool AudioPolicyService::AudioCommandThread::threadLoop()
{
    switch (command->mCommand) {
                case SET_VOLUME: {
                    // lyh 又回到AudioSystem跨进程调用AudioFlinger
                    command->mStatus = AudioSystem::setStreamVolume(data->mStream,
                                                                    data->mVolume,
                                                                    data->mIO);
                    mLock.lock();
                }
                    break;
    }    
}


status_t AudioFlinger::setStreamVolume(audio_stream_type_t stream, float value,
        audio_io_handle_t output)
{
    // lyh 通过继承关系知道【VolumeInterface = PlaybackThread】
    VolumeInterface *volumeInterface = getVolumeInterface_l(output);
    if (volumeInterface == NULL) {
        return BAD_VALUE;
    }
    volumeInterface->setStreamVolume(stream, value);

    return NO_ERROR;
}

void AudioFlinger::PlaybackThread::setStreamVolume(audio_stream_type_t stream, float value)
{
    Mutex::Autolock _l(mLock);
    // 赋值
    mStreamTypes[stream].volume = value;
    // lyh 通知,PlaybackThread线程(例MixerThread)
    broadcast_l();
}