ARC1.5-通过安卓设备的音量条调节功放设备的音量

通过音量条调节设备音量是通过setStreamVolume方法去设置的,接下来主要看一下与ARC相关的代码
base/services/core/java/com/android/server/audio/AudioService.java

private void setStreamVolume(int streamType, int index, int flags,  
        @Nullable AudioDeviceAttributes ada,  
        String callingPackage, String caller, String attributionTag, int uid,  
        boolean hasModifyAudioSettings) {

---
	//这里和adjustStreamVolume一样
	int streamTypeAlias = mStreamVolumeAlias[streamType];  
	VolumeStreamState streamState = mStreamStates[streamTypeAlias];  
  
	final int device = (ada == null)  
        ? getDeviceForStream(streamType)  
        : ada.getInternalType();
---

> [!代码1]
> 	onSetStreamVolume(streamType, index, flags, device, caller, hasModifyAudioSettings);


}
代码1

base/services/core/java/com/android/server/audio/AudioService.java
//setStreamVolumeInt(stream, index, device, false, caller, hasModifyAudioSettings);

private void onSetStreamVolume(int streamType, int index, int flags, int device,  
        String caller, boolean hasModifyAudioSettings) {  
    final int stream = mStreamVolumeAlias[streamType];  
    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*/);  
    }  
    // setting non-zero volume for a muted stream unmutes the stream and vice versa,  
    // except for BT SCO stream where only explicit mute is allowed to comply to BT requirements    
    if (streamType != AudioSystem.STREAM_BLUETOOTH_SCO) {  
        mStreamStates[stream].mute(index == 0);  
    }  
}

base/services/core/java/com/android/server/audio/AudioService.java
//发送MSG_SET_DEVICE_VOLUME消息,后面的流程和2-4接收到MSG_SET_DEVICE_VOLUME消息音量调节的流程一样

private void setStreamVolumeInt(int streamType,  
                                int index,  
                                int device,  
                                boolean force,  
                                String caller, boolean hasModifyAudioSettings) {  
    if (isFullVolumeDevice(device)) {  
        return;  
    }  
    VolumeStreamState streamState = mStreamStates[streamType];  
  
    if (streamState.setIndex(index, device, caller, hasModifyAudioSettings) || force) {  
        // Post message to set system volume (it in turn will post a message  
        // to persist).        sendMsg(mAudioHandler,  
                MSG_SET_DEVICE_VOLUME,  
                SENDMSG_QUEUE,  
                device,  
                0,  
                streamState,  
                0);  
    }  
}

base/services/core/java/com/android/server/audio/AudioService.java

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;  
    }  
    Log.d(TAG,"sug#setStreamVolumeIndexAS#mStreamType = " + mStreamType + "index" + index + "device" + device);  

> [!NOTE]
> 进入AudioSystem,开始真正地设置音量了
>     mAudioSystem.setStreamVolumeIndexAS(mStreamType, index, device);  

}

接下来我们追一下setStreamVolumeIndex后的流程

//在VolumeStreamState 的setStreamVolumeIndex调用AudioSystem的setStreamVolumeIndexAS,开始真正地设置音量

//frameworks/base/service/java/com/android/server/audio/AudioSystem.java
public class AudioSystem{
    ......
    /** Wrapper for native methods called from AudioService */
    public static int setStreamVolumeIndexAS(int stream, int index, int device) {
        if (DEBUG_VOLUME) {
            Log.i(TAG, "setStreamVolumeIndex: " + STREAM_NAMES[stream]
                    + " dev=" + Integer.toHexString(device) + " idx=" + index);
        }
        return setStreamVolumeIndex(stream, index, device); 
    }
    ......
}

//在AudioSystem的setStreamVolumeIndexAS中调用setStreamVolumeIndex方法,setStreamVolumeIndex方法是一个native方法,通过JNI调用AudioSystem native的setStreamVolumeIndex函数:

// frameworks/base/core/jni/android_media_AudioSystem.cpp
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));
}

//在JNI代码中调用AudioSystem的setStreamVolumeIndex函数:

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

//此处创建了一个AudioPolicyService对象,并调用了该对象的setStreamVolume方法。

AudioPolicyService调用了BnAudioPolicyService::onTransact后回去调用自己的setStreamVolumeIndex方法。而setStreamVolumeIndex的实现在AudioPolicyInterfaceImpl.cpp中。

//frameworks/av/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
 status_t AudioPolicyService::setStreamVolumeIndex(audio_stream_type_t stream,
                                                  int index,
                                                  audio_devices_t device)
{
    if (mAudioPolicyManager == NULL) {
        return NO_INIT;
    }
    if (!settingsAllowed()) {
        return PERMISSION_DENIED;
    }
    if (uint32_t(stream) >= AUDIO_STREAM_PUBLIC_CNT) {
        return BAD_VALUE;
    }
    Mutex::Autolock _l(mLock);
    AutoCallerClear acc;
    return mAudioPolicyManager->setStreamVolumeIndex(stream,
                                                    index,
                                                    device);
}

//这里调用mAudioPolicyManager->setStreamVolumeIndex(stream, index,device);,AudioPolicyManager下的setStreamVolumeIndex定义在AudioPolicyManager.cpp中:

//frameworks/av/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
status_t AudioPolicyManager::setStreamVolumeIndex(audio_stream_type_t stream,
                                                  int index,
                                                  audio_devices_t device)
{
    auto attributes = mEngine->getAttributesForStreamType(stream);
    ALOGV("%s: stream %s attributes=%s", __func__,
          toString(stream).c_str(), toString(attributes).c_str());
    return setVolumeIndexForAttributes(attributes, index, device);
}

//在setStreamVolumeIndex调用setVolumeIndexForAttributes函数:

//frameworks/av/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
status_t AudioPolicyManager::setVolumeIndexForAttributes(const audio_attributes_t &attributes,
                                                         int index,
                                                         audio_devices_t device)
{
    // Get Volume group matching the Audio Attributes
    auto group = mEngine->getVolumeGroupForAttributes(attributes);
    if (group == VOLUME_GROUP_NONE) {
        ALOGD("%s: no group matching with %s", __FUNCTION__, toString(attributes).c_str());
        return BAD_VALUE;
    }
    ALOGV("%s: group %d matching with %s", __FUNCTION__, group, toString(attributes).c_str());
    status_t status = NO_ERROR;
    IVolumeCurves &curves = getVolumeCurves(attributes);
    VolumeSource vs = toVolumeSource(group);
    product_strategy_t strategy = mEngine->getProductStrategyForAttributes(attributes);
 
 
    status = setVolumeCurveIndex(index, device, curves);
    if (status != NO_ERROR) {
        ALOGE("%s failed to set curve index for group %d device 0x%X", __func__, group, device);
        return status;
    }
 
 
    audio_devices_t curSrcDevice;
    auto curCurvAttrs = curves.getAttributes();
    if (!curCurvAttrs.empty() && curCurvAttrs.front() != defaultAttr) {
        auto attr = curCurvAttrs.front();
        curSrcDevice = mEngine->getOutputDevicesForAttributes(attr, nullptr, false).types();
    } else if (!curves.getStreamTypes().empty()) {
        auto stream = curves.getStreamTypes().front();
        curSrcDevice = mEngine->getOutputDevicesForStream(stream, false).types();
    } else {
        ALOGE("%s: Invalid src %d: no valid attributes nor stream",__func__, vs);
        return BAD_VALUE;
    }
    curSrcDevice = Volume::getDeviceForVolume(curSrcDevice);
 
 
    // 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 engine for 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 engine for this stream
    // - For default requested device (AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME), apply volume only if
    // no specific device volume value exists for currently selected device.
    for (size_t i = 0; i < mOutputs.size(); i++) {
        sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
        audio_devices_t curDevice = desc->devices().types();
 
 
        if (curDevice & AUDIO_DEVICE_OUT_SPEAKER_SAFE) {
            curDevice |= AUDIO_DEVICE_OUT_SPEAKER;
            curDevice &= ~AUDIO_DEVICE_OUT_SPEAKER_SAFE;
        }
 
 
        // Inter / intra volume group priority management: Loop on strategies arranged by priority
        // If a higher priority strategy is active, and the output is routed to a device with a
        // HW Gain management, do not change the volume
        bool applyVolume = false;
        if (desc->useHwGain()) {
            if (!(desc->isActive(toVolumeSource(group)) || isInCall())) {
                continue;
            }
            for (const auto &productStrategy : mEngine->getOrderedProductStrategies()) {
                auto activeClients = desc->clientsList(true /*activeOnly*/, productStrategy,
                                                       false /*preferredDevice*/);
                if (activeClients.empty()) {
                    continue;
                }
                bool isPreempted = false;
                bool isHigherPriority = productStrategy < strategy;
                for (const auto &client : activeClients) {
                    if (isHigherPriority && (client->volumeSource() != vs)) {
                        ALOGV("%s: Strategy=%d (\nrequester:\n"
                              " group %d, volumeGroup=%d attributes=%s)\n"
                              " higher priority source active:\n"
                              " volumeGroup=%d attributes=%s) \n"
                              " on output %zu, bailing out", __func__, productStrategy,
                              group, group, toString(attributes).c_str(),
                              client->volumeSource(), toString(client->attributes()).c_str(), i);
                        applyVolume = false;
                        isPreempted = true;
                        break;
                    }
                    // However, continue for loop to ensure no higher prio clients running on output
                    if (client->volumeSource() == vs) {
                        applyVolume = true;
                    }
                }
                if (isPreempted || applyVolume) {
                    break;
                }
            }
            if (!applyVolume) {
                continue; // next output
            }
            status_t volStatus = checkAndSetVolume(curves, vs, index, desc, curDevice,
                                                   (vs == toVolumeSource(AUDIO_STREAM_SYSTEM)?
                                                        TOUCH_SOUND_FIXED_DELAY_MS : 0));
            if (volStatus != NO_ERROR) {
                status = volStatus;
            }
            continue;
        }
        if (!(desc->isActive(vs) || isInCall())) {
            continue;
        }
        if ((device != AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME) && ((curDevice & device) == 0)) {
            continue;
        }
        if (device != AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME) {
            curSrcDevice |= device;
            applyVolume = (Volume::getDeviceForVolume(curDevice) & curSrcDevice) != 0;
        } else {
            applyVolume = !curves.hasVolumeIndexForDevice(curSrcDevice);
        }
        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(
                        curves, vs, index, desc, curDevice,
                        ((vs == toVolumeSource(AUDIO_STREAM_SYSTEM))?
                             TOUCH_SOUND_FIXED_DELAY_MS : 0));
            if (volStatus != NO_ERROR) {
                status = volStatus;
            }
        }
    }
    mpClientInterface->onAudioVolumeGroupChanged(group, 0 /*flags*/);
    return status;
}

//在setVolumeIndexForAttributes中调用checkAndSetVolume:

//frameworks/av/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
	status_t AudioPolicyManager::checkAndSetVolume(IVolumeCurves &curves,
                                               VolumeSource volumeSource,
                                               int index,
                                               const sp<AudioOutputDescriptor>& outputDesc,
                                               audio_devices_t device,
                                               int delayMs,
                                               bool force)
{
    // do not change actual attributes volume if the attributes is muted
    if (outputDesc->isMuted(volumeSource)) {
        ALOGVV("%s: volume source %d muted count %d active=%d", __func__, volumeSource,
               outputDesc->getMuteCount(volumeSource), outputDesc->isActive(volumeSource));
        return NO_ERROR;
    }
    VolumeSource callVolSrc = toVolumeSource(AUDIO_STREAM_VOICE_CALL);
    VolumeSource btScoVolSrc = toVolumeSource(AUDIO_STREAM_BLUETOOTH_SCO);
    bool isVoiceVolSrc = callVolSrc == volumeSource;
    bool isBtScoVolSrc = btScoVolSrc == volumeSource;
 
 
    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 sco and call follow same curves, bypass forceUseForComm
    if ((callVolSrc != btScoVolSrc) &&
            ((isVoiceVolSrc && forceUseForComm == AUDIO_POLICY_FORCE_BT_SCO) ||
             (isBtScoVolSrc && forceUseForComm != AUDIO_POLICY_FORCE_BT_SCO))) {
        ALOGV("%s cannot set volume group %d volume with force use = %d for comm", __func__,
             volumeSource, forceUseForComm);
        return INVALID_OPERATION;
    }
    if (device == AUDIO_DEVICE_NONE) {
        device = outputDesc->devices().types();
    }
 
 
    float volumeDb = computeVolume(curves, volumeSource, index, device); //计算volumeDb  
    if (outputDesc->isFixedVolume(device) ||
            // Force VoIP volume to max for bluetooth SCO
            ((isVoiceVolSrc || isBtScoVolSrc) && (device & AUDIO_DEVICE_OUT_ALL_SCO) != 0)) {
        volumeDb = 0.0f;
    }
    outputDesc->setVolume(volumeDb, volumeSource, curves.getStreamTypes(), device, delayMs, force); //AudioPolicyService
 
 
    if (isVoiceVolSrc || isBtScoVolSrc) {
        float voiceVolume;
        // Force voice volume to max or mute for Bluetooth SCO as other attenuations are managed by the headset
        if (isVoiceVolSrc) {
            voiceVolume = (float)index/(float)curves.getVolumeIndexMax();
        } else {
            voiceVolume = index == 0 ? 0.0 : 1.0;
        }
        if (voiceVolume != mLastVoiceVolume) {
            mpClientInterface->setVoiceVolume(voiceVolume, delayMs); 
            mLastVoiceVolume = voiceVolume;
        }
    }
    return NO_ERROR;
}

//AudioOutputDescriptor 在 android 中有两个实现,分别是 SwAudioOutputDescriptor 和 HwAudioOutputDescriptor,音量设置的执行来到 SwAudioOutputDescriptor::setVolume():

//frameworks/av/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
bool SwAudioOutputDescriptor::setVolume(float volumeDb,
                                        VolumeSource vs, const StreamTypeVector &streamTypes,
                                        audio_devices_t device,
                                        uint32_t delayMs,
                                        bool force)
{
    StreamTypeVector streams = streamTypes;
    if (!AudioOutputDescriptor::setVolume(volumeDb, vs, streamTypes, device, delayMs, force)) {
        return false;
    }
    if (streams.empty()) {
        streams.push_back(AUDIO_STREAM_MUSIC);
    }
    for (const auto& devicePort : devices()) {
        // APM loops on all group, so filter on active group to set the port gain,
        // let the other groups set the stream volume as per legacy
        // TODO: Pass in the device address and check against it.
        if (device == devicePort->type() &&
                devicePort->hasGainController(true) && isActive(vs)) {
            ALOGV("%s: device %s has gain controller", __func__, devicePort->toString().c_str());
            // @todo: here we might be in trouble if the SwOutput has several active clients with
            // different Volume Source (or if we allow several curves within same volume group)
            //
            // @todo: default stream volume to max (0) when using HW Port gain?
            float volumeAmpl = Volume::DbToAmpl(0);
            for (const auto &stream : streams) {
                mClientInterface->setStreamVolume(stream, volumeAmpl, mIoHandle, delayMs);
            }
 
 
            AudioGains gains = devicePort->getGains();
            int gainMinValueInMb = gains[0]->getMinValueInMb();
            int gainMaxValueInMb = gains[0]->getMaxValueInMb();
            int gainStepValueInMb = gains[0]->getStepValueInMb();
            int gainValueMb = ((volumeDb * 100)/ gainStepValueInMb) * gainStepValueInMb;
            gainValueMb = std::max(gainMinValueInMb, std::min(gainValueMb, gainMaxValueInMb));
 
 
            audio_port_config config = {};
            devicePort->toAudioPortConfig(&config);
            config.config_mask = AUDIO_PORT_CONFIG_GAIN;
            config.gain.values[0] = gainValueMb;
            return mClientInterface->setAudioPortConfig(&config, 0) == NO_ERROR;
        }
    }
    // Force VOICE_CALL to track BLUETOOTH_SCO stream volume when bluetooth audio is enabled
    float volumeAmpl = Volume::DbToAmpl(getCurVolume(vs));
    if (hasStream(streams, AUDIO_STREAM_BLUETOOTH_SCO)) {
        mClientInterface->setStreamVolume(AUDIO_STREAM_VOICE_CALL, volumeAmpl, mIoHandle, delayMs);
    }
    for (const auto &stream : streams) {
        ALOGV("%s output %d for volumeSource %d, volume %f, delay %d stream=%s", __func__,
              mIoHandle, vs, volumeDb, delayMs, toString(stream).c_str());
        mClientInterface->setStreamVolume(stream, volumeAmpl, mIoHandle, delayMs);
    }
    return true;
}

//SwAudioOutputDescriptor 又通过 AudioPolicyClientInterface 设置音量;AudioPolicyClientInterface 的实现为 AudioPolicyService::AudioPolicyClient,设置音量的动作经 AudioPolicyService::AudioPolicyClient 转回 AudioPolicyService,只是这次调用的是 AudioPolicyService::setStreamVolume();

//frameworks/av/services/audiopolicy/service/AudioPolicyService.cpp
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);
}
 
status_t AudioPolicyService::AudioCommandThread::volumeCommand(audio_stream_type_t stream,
    float volume,audio_io_handle_t output,int delayMs)
{
    ...(封装了一下data跟command)
    return sendCommand(command, delayMs);
}
 
status_t AudioPolicyService::AudioCommandThread::sendCommand(sp<AudioCommand>& command, int delayMs) {...(一些命令队列的操作)}
 
// 处理函数
bool AudioPolicyService::AudioCommandThread::threadLoop()
{
    ...
    while (!exitPending())
    {
        ...
        switch (command->mCommand) {
        ...
        case SET_VOLUME: 
            ...(Lock)
            VolumeData *data = (VolumeData *)command->mParam.get();
            command->mStatus = AudioSystem::setStreamVolume(data->mStream,
                data->mVolume,data->mIO); 
        break;
        ...
    }
}

//AudioPolicyService异步执行这个操作,最后会转到AudioSystem的setStreamVolume:

//frameworks/av/media/libaudioclient/AudioSystem.cpp
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;
}

//在AudioSystem的setStreamVolume中会调用AudioFlinger的setStreamVolume:

//frameworks/base/media/java/android/media/audioflinger/AudioFlinger.cpp
status_t AudioFlinger::setStreamVolume(audio_stream_type_t stream, float value,
        audio_io_handle_t output)
{
    // check calling permissions
    if (!settingsAllowed()) {
        return PERMISSION_DENIED;
    }
 
 
    status_t status = checkStreamType(stream);
    if (status != NO_ERROR) {
        return status;
    }
    if (output == AUDIO_IO_HANDLE_NONE) {
        return BAD_VALUE;
    }
    LOG_ALWAYS_FATAL_IF(stream == AUDIO_STREAM_PATCH && value != 1.0f,
                        "AUDIO_STREAM_PATCH must have full scale volume");
 
 
    AutoMutex lock(mLock);
    VolumeInterface *volumeInterface = getVolumeInterface_l(output);
    if (volumeInterface == NULL) {
        return BAD_VALUE;
    }
    volumeInterface->setStreamVolume(stream, value);
 
 
    return NO_ERROR;
}

//AudioFlinger会去获取output对应的PlaybackThread并设置PlaybackThread的音量,如果output == AUDIOIOHANDLE_NONE,则设置所有PlaybackThread的音量。

PlaybackThread设置mStreamTypes的volume。并唤醒PlaybackThread线程

//frameworks/base/media/java/android/media/audioflinger/Threads.cpp
void AudioFlinger::PlaybackThread::setStreamVolume(audio_stream_type_t stream, float value)
{
    Mutex::Autolock _l(mLock);
    mStreamTypes[stream].volume = value;
    broadcast_l();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值