您的当前位置:首页正文

Android13 AudioManager setStreamVolume流程分析

2024-11-13 来源:个人技术集锦

AudioService setStreamVolume流程分析

一、Android的音量调节

Android的音量调节分3个部分,分别是master volume(硬件音量,控制声卡),stream volume(流音量)和track volume(app音量)。

master volume:设置它等于设置所有的stream volume和track volume。它可以写到声卡里面去,控制所有声音的音量。也可以不写到声卡里面去,而是作为一个乘数因子来影响所有的音量。换句话说:master volume 可以设置所有的AudioTrack volume和stream volume。

stream volume:设置某一stream的音量,Android系统中支持10种stream。各种stream的音量也可以单独设置、互不影响。比如"音乐音量"不应该影响到"来电振铃"、"闹钟"、"通话"的音量。

stream volume alias:设置的是同一组stream音量,分组在Android源码中称之为"别名",即alias。比如在电话中,5种stream(STREAM_SYSTEM、STREAM_RING、STREAM_NOTIFICATION、STREAM_SYSTEM_ENFORCED、STREAM_DTMF)的alias都是STREAM_RING,那么对应的滑动条即可控制这5种stream的音量。

AudioTrack volume: 单个App设置音量时设置的是这个,它只影响本App的音量。

除此之外CarAudioManager通过SetGroupVolume设置组音量。

stream的种类

Android系统中有10种stream,在system/core/include/system/audio.h中定义,但把这10种stream分成组,属于同一组的stream具有相同的别名(alias)。在我们设置音量时,一个音量调节滑动条具有一个alias,具有相同alias的stream都会受到这个滑动条的影响。stream与alias的关系(参考)如下所示:



流类型最大音量小音量最默认音量VOICE/DEFAULTTELEVISION

0

STREAM_VOICE_CALL

5

1

4

STREAM_VOICE_CALL

STREAM_MUSIC

1

STREAM_SYSTEM

7

0

7

STREAM_RING

STREAM_MUSIC

2

STREAM_RING

7

0

7

STREAM_RING

STREAM_MUSIC

3

STREAM_MUSIC

15

0

5

STREAM_MUSIC

STREAM_MUSIC

4

STREAM_ALARM

7

0

6

STREAM_ALARM

STREAM_MUSIC

5

STREAM_NOTIFICATION

7

0

5

STREAM_RING

STREAM_MUSIC

6

STREAM_BLUETOOTH_SCO

15

0

7

STREAM_BLUETOOTH_SCO

STREAM_MUSIC

7

STREAM_SYSTEM_ENFORCED

7

0

7

STREAM_RING

STREAM_MUSIC

8

STREAM_DTMF

15

0

5

STREAM_RING

STREAM_MUSIC

9

STREAM_TTS

15

0

5

STREAM_MUSIC

STREAM_MUSIC

10

STREAM_ACCESSIBILITY

15

0

5

STREAM_MUSIC

STREAM_MUSIC

声音播放的两种路径

MixerThread:APP对音量的设置不会影响到声卡的硬件音量,而只会影响APP的音频数据的幅值(变小或放大),这些音频数据最终被混合后传给声卡。

DirectOutputThread(比如HDMI,单个音频应用程序单独使用一个声卡):同一时间里只有一个APP、只有一个AudioTrack使用它,所以该AudioTrack的音量可以被DirectOutputThread直接用来设置硬件音量,这种声卡使用的不多。若配置文件中参数信息包含"flags AUDIO_OUTPUT_FLAG_DIRECT",则表示这个声卡可以被某个App独占。App就能以DirectOutputThread的形式来使用这个声卡。

混音的逻辑

app1:混音数据1 = 音频数据1 * master_volume * stream1_volume * AudioTrack1_volume

app2:混音数据2 = 音频数据2 * master_volume * stream2_volume * AudioTrack2_volume

app3:混音数据3 = 音频数据3 * master_volume * stream3_volume * AudioTrack3_volume

混合在一起: 最终混音 =混音数据1+混音数据2+混音数据3,然后把混合后的数据写给硬件。

二、AudioVolume相关方法

1、AudioManager方法

  • void adjustVolume(int direction,int flags):调整最相关的数据流的音量

  • void adjustStreamVolume(int streamType, int direction, int flags):调整指定类型的声音

  • void setStreamVolume (int streamType, int index, int flags):直接设置指定类型的音量值

  • void setStreamMute(int streamType,booleanstate):将指定类型的声音调整为静音

  • int getStreamVolume(int streamType):返回特定数据流的当前音量

  • int getStreamMaxVolume(int streamType):返回特定流的最大音量

  • boolean isMasterMute():是否为主静音状态

  • void setMasterMute(boolean mute, int flags):设置主静音状态

2、AudioService方法

  • boolean isStreamMute(int streamType):指定流是否为Mute状态

  • boolean isMasterMute():是否为主静音状态

  • int getStreamVolume(int streamType):返回特定数据流的当前音量

  • int getStreamMinVolume(int streamType):返回特定流的最晓音量

  • int getStreamMaxVolume(int streamType):返回特定流的最大音量

  • int getVolumeIndexForAttributes(in AudioAttributes aa):返回音量索引

  • int getMaxVolumeIndexForAttributes(in AudioAttributes aa):返回最大音量索引

  • int getMinVolumeIndexForAttributes(in AudioAttributes aa):返回最小音量索引

  • int getLastAudibleStreamVolume(int streamType):返回最后听得见流音量

  • List<AudioVolumeGroup> getAudioVolumeGroups():返回获取音频音量组

  • void adjustStreamVolume(int streamType, int direction, int flags, String callingPackage):调整指定类型的声音

  • void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags, String callingPackage, String caller):

  • void setStreamVolume(int streamType, int index, int flags, String callingPackage):直接设置指定类型的音量值

  • void setMasterMute(boolean mute, int flags, String callingPackage, int userId):设置主静音状态

  • void setVolumeIndexForAttributes(in AudioAttributes aa, int index, int flags, String callingPackage):设置音量索引

  • void forceRemoteSubmixFullVolume(boolean startForcing, IBinder cb):

三、Volume设定分析

1、StreamVolume流程

音量初始设置



 setStreamVolume



adjustVolume



2、setStreamVolume代码分析

首先看AudioManager的setStreamVolume方法:

//frameworks/base/media/java/android/media/AudioManager.java
public class AudioManager {
    ......
    public void setStreamVolume(int streamType, int index, int flags) {
        final IAudioService service = getService();
        try {
    //调用AudioService的setStreamVolume方法
            service.setStreamVolume(streamType, index, flags, getContext().getOpPackageName()); 
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }
    ......
}

在AudioManager 中调用了AudioService的setStreamVolume方法:

//frameworks/base/service/java/com/android/server/audio/AudioService.java
public class AudioService extends IAudioService.Stub
        implements AccessibilityManager.TouchExplorationStateChangeListener,
            AccessibilityManager.AccessibilityServicesStateChangeListener {
    ......
    /** The controller for the volume UI. */
    private final VolumeController mVolumeController = new VolumeController();
    ......
    public void setStreamVolume(int streamType, int index, int flags, String callingPackage) {
        //验证流类型是否合法
        if ((streamType == AudioManager.STREAM_ACCESSIBILITY) && !canChangeAccessibilityVolume()) {
            Log.w(TAG, "Trying to call setStreamVolume() for a11y without"
                    + " CHANGE_ACCESSIBILITY_VOLUME  callingPackage=" + callingPackage);
            return;
        }
        if ((streamType == AudioManager.STREAM_VOICE_CALL) && (index == 0)
                && (mContext.checkCallingOrSelfPermission(
                    android.Manifest.permission.MODIFY_PHONE_STATE)
                    != PackageManager.PERMISSION_GRANTED)) {
            Log.w(TAG, "Trying to call setStreamVolume() for STREAM_VOICE_CALL and index 0 without"
                    + " MODIFY_PHONE_STATE  callingPackage=" + callingPackage);
            return;
        }
        sVolumeLogger.log(new VolumeEvent(VolumeEvent.VOL_SET_STREAM_VOL, streamType,
                index/*val1*/, flags/*val2*/, callingPackage));
        setStreamVolume(streamType, index, flags, callingPackage, callingPackage,
                Binder.getCallingUid());
    }


    private void setStreamVolume(int streamType, int index, int flags, String callingPackage,
            String caller, int uid) {
        if (DEBUG_VOL) {
            Log.d(TAG, "setStreamVolume(stream=" + streamType+", index=" + index
                    + ", calling=" + callingPackage + ")");
        }
        if (mUseFixedVolume) {
            return;
        }


        //确认流类型
        ensureValidStreamType(streamType);
        //获取别名,安卓在通过流设置音量时可以通过传入一个流类型通过mStreamVolumeAlias查找隐射的流类型来达到通过一个流来设置另一个流的目的。
     (此处比较绕,简单的理解就是我可以通过使用STREAM_RING 通过mStreamVolumeAlias来映射到STREAM_MUSIC这个流以达到改变STREAM_RING来控制STREAM_MUSIC的目的)。
        int streamTypeAlias = mStreamVolumeAlias[streamType];
        VolumeStreamState streamState = mStreamStates[streamTypeAlias];
        //获取当前流的设备(如喇叭,蓝牙,以下所设置以及保存的音量是和设备进行保存的)
        final int device = getDeviceForStream(streamType);
        //上一次设置的音量值
        int oldIndex;


        // skip a2dp absolute volume control request when the device
        // is not an a2dp device
        if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
            (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
            return;
        }
        // If we are being called by the system (e.g. hardware keys) check for current user
        // so we handle user restrictions correctly.
        if (uid == android.os.Process.SYSTEM_UID) {
            uid = UserHandle.getUid(getCurrentUserId(), UserHandle.getAppId(uid));
        }
        if (mAppOps.noteOp(STREAM_VOLUME_OPS[streamTypeAlias], uid, callingPackage)
                != AppOpsManager.MODE_ALLOWED) {
            return;
        }


        if (isAndroidNPlus(callingPackage)
                && wouldToggleZenMode(getNewRingerMode(streamTypeAlias, index, flags))
                && !mNm.isNotificationPolicyAccessGrantedForPackage(callingPackage)) {
            throw new SecurityException("Not allowed to change Do Not Disturb state");
        }


        if (!volumeAdjustmentAllowedByDnd(streamTypeAlias, flags)) {
            return;
        }


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


//获取旧的音量值
            oldIndex = streamState.getIndex(device);
     //对音量值进行某些操作(在音量设置逻辑中对传入的值进行修改,达到对不同流对应的音量大小进行分别控制的目的,简单说大概就是单位换算的意思)
            index = rescaleIndex(index * 10, streamType, streamTypeAlias);


            if (streamTypeAlias == AudioSystem.STREAM_MUSIC
                    && (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0
                    && (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
                if (DEBUG_VOL) {
                    Log.d(TAG, "setStreamVolume postSetAvrcpAbsoluteVolumeIndex index=" + index
                            + "stream=" + streamType);
                }
                mDeviceBroker.postSetAvrcpAbsoluteVolumeIndex(index / 10);
            }


            if ((device & AudioSystem.DEVICE_OUT_HEARING_AID) != 0
                    && streamType == getHearingAidStreamType()) {
                Log.i(TAG, "setStreamVolume postSetHearingAidVolumeIndex index=" + index
                        + " stream=" + streamType);
                mDeviceBroker.postSetHearingAidVolumeIndex(index, streamType);
            }


            if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
                setSystemAudioVolume(oldIndex, index, getStreamMaxVolume(streamType), flags);  // 这里是和hdmi相关,不用管
            }


            flags &= ~AudioManager.FLAG_FIXED_VOLUME;
            if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
                    ((device & mFixedVolumeDevices) != 0)) {
                flags |= AudioManager.FLAG_FIXED_VOLUME;


                // volume is either 0 or max allowed for fixed volume devices
                if (index != 0) {
                    if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
                            (device & mSafeMediaVolumeDevices) != 0) {
                        index = safeMediaVolumeIndex(device);
                    } else {
                        index = streamState.getMaxIndex();
                    }
                }
            }


            if (!checkSafeMediaVolume(streamTypeAlias, index, device)) {
                mVolumeController.postDisplaySafeVolumeWarning(flags);
                mPendingVolumeCommand = new StreamVolumeCommand(
                                                    streamType, index, flags, device);
            } else {
                onSetStreamVolume(streamType, index, flags, device, caller); //此处时真正设置音量的地方,调用onSetStreamVolume
                index = mStreamStates[streamType].getIndex(device);
            }
        }
        synchronized (mHdmiClientLock) {
            if (mHdmiManager != null &&
                    mHdmiAudioSystemClient != null &&
                    mHdmiSystemAudioSupported &&
                    streamTypeAlias == AudioSystem.STREAM_MUSIC &&
                    (oldIndex != index)) {
                final long identity = Binder.clearCallingIdentity();
                mHdmiAudioSystemClient.sendReportAudioStatusCecCommand(
                        false, getStreamVolume(AudioSystem.STREAM_MUSIC),
                        getStreamMaxVolume(AudioSystem.STREAM_MUSIC),
                        isStreamMute(AudioSystem.STREAM_MUSIC));
                Binder.restoreCallingIdentity(identity);
            }
        }
        sendVolumeUpdate(streamType, oldIndex, index, flags, device); //发送更新音量的信息。
    }
    ......
    private void onSetStreamVolume(int streamType, int index, int flags, int device,
            String caller) {
        final int stream = mStreamVolumeAlias[streamType];
        setStreamVolumeInt(stream, index, device, false, caller); //
        // 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);
        }
    }
    ......
    private void setStreamVolumeInt(int streamType,
                                    int index,
                                    int device,
                                    boolean force,
                                    String caller) {
        if ((device & mFullVolumeDevices) != 0) {
            return;
        }
       
        VolumeStreamState streamState = mStreamStates[streamType];


//先调用streamState.setIndex将音量设置到表里面保存起来    
        if (streamState.setIndex(index, device, caller) || force) {
            // Post message to set system volume (it in turn will post a message
            // to persist).
    //发送消息给handler设置音量
            sendMsg(mAudioHandler,
                    MSG_SET_DEVICE_VOLUME,
                    SENDMSG_QUEUE,
                    device,
                    0,
                    streamState,
                    0);
        }
    }
    ......
}

AudioService的setStreamVolume方法中调用onSetStreamVolume->setStreamVolumeInt然后发送MSG_SET_DEVICE_VOLUME给AudioHandler,AudioHandler处理如下:

//frameworks/base/service/java/com/android/server/audio/AudioService.java
public class AudioService extends IAudioService.Stub
        implements AccessibilityManager.TouchExplorationStateChangeListener,
            AccessibilityManager.AccessibilityServicesStateChangeListener {
    ......
    /** Handles internal volume messages in separate volume thread. */
    private class AudioHandler extends Handler {
    ......
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_SET_DEVICE_VOLUME:
                    setDeviceVolume((VolumeStreamState) msg.obj, msg.arg1);  //调用setDeviceVolume
                    break;
        }
    }
    ......
}

我们接着分析setDeviceVolume的处理:

//frameworks/base/service/java/com/android/server/audio/AudioService.java
public class AudioService extends IAudioService.Stub
        implements AccessibilityManager.TouchExplorationStateChangeListener,
            AccessibilityManager.AccessibilityServicesStateChangeListener {
    ......
    void setDeviceVolume(VolumeStreamState streamState, int device) {


    final boolean isAvrcpAbsVolSupported = mDeviceBroker.isAvrcpAbsoluteVolumeSupported();


        synchronized (VolumeStreamState.class) {
            // Apply volume
    //调用streamState.applyDeviceVolume_syncVSS
            streamState.applyDeviceVolume_syncVSS(device, isAvrcpAbsVolSupported);


            // 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) && isAvrcpAbsVolSupported
                            && ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0)) {
                        mStreamStates[streamType].applyDeviceVolume_syncVSS(device,
                                isAvrcpAbsVolSupported);
                    }
                    mStreamStates[streamType].applyDeviceVolume_syncVSS(streamDevice,
                            isAvrcpAbsVolSupported);
                }
            }
        }
        // Post a persist volume msg
        sendMsg(mAudioHandler,
                MSG_PERSIST_VOLUME,
                SENDMSG_QUEUE,
                device,
                0,
                streamState,
                PERSIST_DELAY);
    }
    ......
}

setDeviceVolume方法中调用内部类VolumeStreamState对象的applyDeviceVolume_syncVSS方法:

//frameworks/base/service/java/com/android/server/audio/AudioService.java
public class AudioService extends IAudioService.Stub
        implements AccessibilityManager.TouchExplorationStateChangeListener,
            AccessibilityManager.AccessibilityServicesStateChangeListener {
    ......
    private class VolumeStreamState {
        // must be called while synchronized VolumeStreamState.class
       void applyDeviceVolume_syncVSS(int device, boolean isAvrcpAbsVolSupported) {
            int index;
            if (mIsMuted) {
                index = 0;
            } else if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 && isAvrcpAbsVolSupported) {
                index = getAbsoluteVolumeIndex((getIndex(device) + 5)/10);
            } else if ((device & mFullVolumeDevices) != 0) {
                index = (mIndexMax + 5)/10;
            } else if ((device & AudioSystem.DEVICE_OUT_HEARING_AID) != 0) {
                index = (mIndexMax + 5)/10;
            } else {
                index = (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 && !mIsMuted) {
                index = 1;
            }
     //进入AudioSystem,开始真正地设置音量了
            AudioSystem.setStreamVolumeIndexAS(mStreamType, index, device); 
        }
    ......
    }
    ......
}

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

整体的概要流程图如下:

Top