Android10 音频系统之音量调节流程

xref: /frameworks/base/media/java/android/media/AudioManager.java

public void setStreamVolume(int streamType, int index, int flags) {
    final IAudioService service = getService();
    try {
        service.setStreamVolume(streamType, index, flags, getContext().getOpPackageName());
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }
}

        当我们通过音量控制条调整音量大小的时候,会通过调用AudioManager.setStreamVolume设置音量的大小。AudioManager会通过aidl通信调用AudioService的setStreamVolume方法。

xref: /frameworks/base/services/core/java/com/android/server/audio/AudioService.java

/** @see AudioManager#setStreamVolume(int, int, int) */
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;
    }
    mVolumeLogger.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);
    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 (mSafeMediaVolumeState) {
        // 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) {
            synchronized (mA2dpAvrcpLock) {
                if (mA2dp != null && mAvrcpAbsVolSupported) {
                    mA2dp.setAvrcpAbsoluteVolume(index / 10);
                }
            }
        }

        if ((device & AudioSystem.DEVICE_OUT_HEARING_AID) != 0) {
            setHearingAidVolume(index, streamType);
        }

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

        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);
            index = mStreamStates[streamType].getIndex(device);
        }
    }
    sendVolumeUpdate(streamType, oldIndex, index, flags);
}


........................................................................................


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

    if (streamState.setIndex(index, device, caller) || 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);
    }
}


.........................................................................................


private class AudioHandler extends Handler {

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

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

            case MSG_SET_ALL_VOLUMES:
                setAllVolumes((VolumeStreamState) msg.obj);
                break;

            .........................................................................................
			
        }
    }
}


.........................................................................................


/*package*/ void setDeviceVolume(VolumeStreamState streamState, int device) {

    final boolean isAvrcpAbsVolSupported = mDeviceBroker.isAvrcpAbsoluteVolumeSupported();

    synchronized (VolumeStreamState.class) {
        // Apply volume
        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);

}


..................................................................................


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.setStreamVolumeIndexAS(mStreamType, index, device);
}

// must be called while synchronized VolumeStreamState.class
/*package*/ 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);
}

        通过checkSafeMediaVolume来检查当前是否可设置音量,调节音量大小走else语句onSetStreamVolume方法。

        在setDeviceVolume方法里面通过applyDeviceVolume_syncVSS设置应用音量,接着更改所有用此别名的流,确保音量在A2DP设备上也达到最大。在applyDeviceVolume_syncVSS中会判断index是否为0,如果为0则是静音,否则会通过设备类型类设置index。

        最终会走到setStreamVolumeIndex方法调用AudioSystem.setStreamVolumeIndexAS(mStreamType, index, device)。

xref: /frameworks/base/media/java/android/media/AudioSystem.java        

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

.....................................................................................

private static native int setStreamVolumeIndex(int stream, int index, int device);

        setStreamVolumeIndex是一个native方法,对应的是android_media_AudioSystem.cpp里面的setStreamVolumeIndex

xref: /frameworks/base/core/jni/android_media_AudioSystem.cpp

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

        调用AudioSystem的setStreamVolumeIndex方法

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


.................................................................................


const sp<IAudioPolicyService> AudioSystem::get_audio_policy_service()
{
    sp<IAudioPolicyService> ap;
    sp<AudioPolicyServiceClient> apc;
    {
        Mutex::Autolock _l(gLockAPS);
        if (gAudioPolicyService == 0) {
            sp<IServiceManager> sm = defaultServiceManager();
            sp<IBinder> binder;
            do {
                binder = sm->getService(String16("media.audio_policy"));
                if (binder != 0)
                    break;
                ALOGW("AudioPolicyService not published, waiting...");
                usleep(500000); // 0.5 s
            } while (true);
            if (gAudioPolicyServiceClient == NULL) {
                gAudioPolicyServiceClient = new AudioPolicyServiceClient();
            }
            binder->linkToDeath(gAudioPolicyServiceClient);
            gAudioPolicyService = interface_cast<IAudioPolicyService>(binder);
            LOG_ALWAYS_FATAL_IF(gAudioPolicyService == 0);
            apc = gAudioPolicyServiceClient;
            // Make sure callbacks can be received by gAudioPolicyServiceClient
            ProcessState::self()->startThreadPool();
        }
        ap = gAudioPolicyService;
    }
    if (apc != 0) {
        int64_t token = IPCThreadState::self()->clearCallingIdentity();
        ap->registerClient(apc);
        ap->setAudioPortCallbacksEnabled(apc->isAudioPortCbEnabled());
        ap->setAudioVolumeGroupCallbacksEnabled(apc->isAudioVolumeGroupCbEnabled());
        IPCThreadState::self()->restoreCallingIdentity(token);
    }

    return ap;
}

        get_audio_policy_service通过Binder机制获取到一个Service,这个Service的实现类是AudioPolicyInterfaceImpl.cpp

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

        调用AudioPolicyManager的setStreamVolumeIndex方法

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

............................................................................................


status_t Audi
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值