1. 程式人生 > >Android音量設定流程(android8.0)

Android音量設定流程(android8.0)

最近一直在解安卓audio部分的bug,其中最多的就是音量設定方面的問題,在這裡把自己學習到的一些東西記錄一下,以供參考。

安卓java部分的音量設定首先呼叫到AudioManager.java中
在這裡有兩種方法可以設定音量setStreamVolume和adjustStreamVolume
setStreamVolume:傳入index直接設定音量值
adjustStreamVolume:傳入direction,根據direction和獲取到的步長設定音量。

由於我們用到的是setStreamVolume方法,所以通過setStreamVolume向下看,其實如果再去看adjustStreamVolume其實也是殊途同歸。

1.setStreamVolume(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(); } }

在此處呼叫了AudioService的setStreamVolume方法。此處傳入的streamType和index分別為設定的流型別和音量值。

關於streamType:安卓在聲音方面定義了多種流的型別以控制不同的聲音(比如區分音樂和鈴聲以及系統提示音等)

    /** Used to identify the volume of audio streams for phone calls */
    public static final int STREAM_VOICE_CALL = AudioSystem.STREAM_VOICE_CALL;
    /** Used to identify the volume of audio streams for system sounds */
public static final int STREAM_SYSTEM = AudioSystem.STREAM_SYSTEM; /** Used to identify the volume of audio streams for the phone ring */ public static final int STREAM_RING = AudioSystem.STREAM_RING; /** Used to identify the volume of audio streams for music playback */ public static final int STREAM_MUSIC = AudioSystem.STREAM_MUSIC; /** Used to identify the volume of audio streams for alarms */ public static final int STREAM_ALARM = AudioSystem.STREAM_ALARM; /** Used to identify the volume of audio streams for notifications */ public static final int STREAM_NOTIFICATION = AudioSystem.STREAM_NOTIFICATION; /** @hide Used to identify the volume of audio streams for phone calls when connected * to bluetooth */ public static final int STREAM_BLUETOOTH_SCO = AudioSystem.STREAM_BLUETOOTH_SCO; /** @hide Used to identify the volume of audio streams for enforced system sounds * in certain countries (e.g camera in Japan) */ public static final int STREAM_SYSTEM_ENFORCED = AudioSystem.STREAM_SYSTEM_ENFORCED; /** Used to identify the volume of audio streams for DTMF Tones */ public static final int STREAM_DTMF = AudioSystem.STREAM_DTMF; /** @hide Used to identify the volume of audio streams exclusively transmitted through the * speaker (TTS) of the device */ public static final int STREAM_TTS = AudioSystem.STREAM_TTS; /** Used to identify the volume of audio streams for accessibility prompts */ public static final int STREAM_ACCESSIBILITY = AudioSystem.STREAM_ACCESSIBILITY;

我們在AudioManager.java中可以看到原始碼對各種流型別進行了解釋,並且呼叫AudioSystem中的變數進行了賦值。

   /** Used to identify the default audio stream volume */
    public static final int STREAM_DEFAULT = -1;
    /** Used to identify the volume of audio streams for phone calls */
    public static final int STREAM_VOICE_CALL = 0;
    /** Used to identify the volume of audio streams for system sounds */
    public static final int STREAM_SYSTEM = 1;
    /** Used to identify the volume of audio streams for the phone ring and message alerts */
    public static final int STREAM_RING = 2;
    /** Used to identify the volume of audio streams for music playback */
    public static final int STREAM_MUSIC = 3;
    /** Used to identify the volume of audio streams for alarms */
    public static final int STREAM_ALARM = 4;
    /** Used to identify the volume of audio streams for notifications */
    public static final int STREAM_NOTIFICATION = 5;
    /** Used to identify the volume of audio streams for phone calls when connected on bluetooth */
    public static final int STREAM_BLUETOOTH_SCO = 6;
    /** Used to identify the volume of audio streams for enforced system sounds in certain
     * countries (e.g camera in Japan) */
    public static final int STREAM_SYSTEM_ENFORCED = 7;
    /** Used to identify the volume of audio streams for DTMF tones */
    public static final int STREAM_DTMF = 8;
    /** Used to identify the volume of audio streams exclusively transmitted through the
     *  speaker (TTS) of the device */
    public static final int STREAM_TTS = 9;
    /** Used to identify the volume of audio streams for accessibility prompts */
    public static final int STREAM_ACCESSIBILITY = 10;
    /**

2.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;
        }
        setStreamVolume(streamType, index, flags, callingPackage, callingPackage,
                Binder.getCallingUid());
    }

此處再呼叫AudioService中的setStreamVolume的過載函式,該函式多傳入了一個Binder.getCallingUid(),此處用到了binder的方法獲取呼叫端的UID來判斷呼叫者的身份,有興趣的可以去了解binder相關的內容,此處影響不大不多做解釋。

 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 (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 (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 = mSafeMediaVolumeIndex;
                    } else {
                        index = streamState.getMaxIndex();
                    }
                }
            }

            if (!checkSafeMediaVolume(streamTypeAlias, index, device)) {
                mVolumeController.postDisplaySafeVolumeWarning(flags);
                mPendingVolumeCommand = new StreamVolumeCommand(
                                                    streamType, index, flags, device);
            } else {
                //此處時真正設定音量的地方,呼叫onSetStreamVolume。上面做的那些判斷有需要或者遇到問題再去查,此處不一一解釋了。
                onSetStreamVolume(streamType, index, flags, device, caller);
                index = mStreamStates[streamType].getIndex(device);
            }
        }
        sendVolumeUpdate(streamType, oldIndex, index, flags);
    }

onSetStreamVolume

    private void onSetStreamVolume(int streamType, int index, int flags, int device,
            String caller) {
        final int stream = mStreamVolumeAlias[streamType];
        //呼叫setstreamVolumeInt
        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
        mStreamStates[stream].mute(index == 0);
    }

setstreamVolumeInt

    private void setStreamVolumeInt(int streamType,
                                    int index,
                                    int device,
                                    boolean force,
                                    String caller) {
        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);
        }
    }

handleMessage

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

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

setDeviceVolume

        private void setDeviceVolume(VolumeStreamState streamState, int device) {

            synchronized (VolumeStreamState.class) {
                // Apply volume
                //呼叫streamState.applyDeviceVolume_syncVSS
                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 &&
                                ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0)) {
                            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);

        }

streamState.applyDeviceVolume_syncVSS

        public void applyDeviceVolume_syncVSS(int device) {
            int index;
            if (mIsMuted) {
                index = 0;
            } else if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 && mAvrcpAbsVolSupported) {
                index = getAbsoluteVolumeIndex((getIndex(device) + 5)/10);
            } else if ((device & mFullVolumeDevices) != 0) {
                index = (mIndexMax + 5)/10;
            } else {
                index = (getIndex(device) + 5)/10;
            }
            //進入AudioSystem,開始真正地設定音量了
            AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
        }

3.AudioSystem.java

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

這裡呼叫了一個native函式,其中涉及到JNI的知識,有興趣的可以去查詢資料學習。這個native函式可以在android_media_AudioSystem.cpp 中查詢到。

4.android_media_AudioSystem.cpp

static const JNINativeMethod gMethods[] = {
    {"setParameters",        "(Ljava/lang/String;)I", (void *)android_media_AudioSystem_setParameters},
    .....................................................
    {"setForceUse",         "(II)I",    (void *)android_media_AudioSystem_setForceUse},
    {"getForceUse",         "(I)I",     (void *)android_media_AudioSystem_getForceUse},
    {"initStreamVolume",    "(III)I",   (void *)android_media_AudioSystem_initStreamVolume},
    //查詢到JAVA層的setStreamVolumeIndex函式對應的是c++層android_media_AudioSystem_setStreamVolumeIndex
    {"setStreamVolumeIndex","(III)I",   (void *)android_media_AudioSystem_setStreamVolumeIndex},
    {"getStreamVolumeIndex","(II)I",    (void *)android_media_AudioSystem_getStreamVolumeIndex},
    {"setMasterVolume",     "(F)I",     (void *)android_media_AudioSystem_setMasterVolume},
    ......................................................

android_media_AudioSystem_setStreamVolumeIndex

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

此處呼叫AudioSystem::setStreamVolumeIndex(此時的是AudioSystem.cpp的函式)

5.AudioSystem.cpp
setStreamVolumeIndex

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

此處建立了一個aps物件,並呼叫了該物件的setStreamVolume方法。 所以我們先看AudioSystem::get_audio_policy_service()返回了一個什麼物件。

AudioSystem::get_audio_policy_service()

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);
            //這裡使用了interface_cast並且傳入了一個binder,這裡也是binder相關的知識,這裡不對binder做過多解釋,
            只根據這音量設定的流程做一定說明
            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) {
        ap->registerClient(apc);
    }

    return ap;
}

6.IInterface.h

上面的interface_cast(binder),interface_cast是一個模版,在frameworks\native\include\binder\IInterface.h中定義如下

template<typename INTERFACE>
inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj)
{
    return INTERFACE::asInterface(obj);
}

展開後返回的是 IAudioPolicyService::asInterface(binder)
此時asInterface是在IAudioPolicyService作用域下,所以再去IAudioPolicyService.h查詢asInterface

7.IAudioPolicyService.h

在IAudioPolicyService中發現

DECLARE_META_INTERFACE(AudioPolicyService);
這一個巨集,這個巨集的定義也在frameworks\native\include\binder\IInterface.h中。

8.IInterface.h

#define DECLARE_META_INTERFACE(INTERFACE)                               \
    static const ::android::String16 descriptor;                        \
    static ::android::sp<I##INTERFACE> asInterface(                     \
            const ::android::sp<::android::IBinder>& obj);              \
    virtual const ::android::String16& getInterfaceDescriptor() const;  \
    I##INTERFACE();                                                     \
    virtual ~I##INTERFACE();                                            \

其中static ::android::sp

#define IMPLEMENT_META_INTERFACE(INTERFACE, NAME)                       \
    const ::android::String16 I##INTERFACE::descriptor(NAME);           \
    const ::android::String16&                                          \
            I##INTERFACE::getInterfaceDescriptor() const {              \
        return I##INTERFACE::descriptor;                                \
    }                                                                   \
    ::android::sp<I##INTERFACE> I##INTERFACE::asInterface(              \
            const ::android::sp<::android::IBinder>& obj)               \
    {                                                                   \
        ::android::sp<I##INTERFACE> intr;                               \
        if (obj != NULL) {                                              \
            intr = static_cast<I##INTERFACE*>(                          \
                obj->queryLocalInterface(                               \
                        I##INTERFACE::descriptor).get());               \
            if (intr == NULL) {                                         \
                intr = new Bp##INTERFACE(obj);                          \
            }                                                           \
        }                                                               \
        return intr;                                                    \
    }                                                                   \
    I##INTERFACE::I##INTERFACE() { }                                    \
    I##INTERFACE::~I##INTERFACE() { }                                   \

其中

::android::sp<I##INTERFACE> I##INTERFACE::asInterface(              \
            const ::android::sp<::android::IBinder>& obj)               \
    {                                                                   \
        ::android::sp<I##INTERFACE> intr;                               \
        if (obj != NULL) {                                              \
            intr = static_cast<I##INTERFACE*>(                          \
                obj->queryLocalInterface(                               \
                        I##INTERFACE::descriptor).get());               \
            if (intr == NULL) {                                         \
                intr = new Bp##INTERFACE(obj);                          \
            }                                                           \
        }                                                               \
        return intr;                                                    \
    }                       

返回的intr 就是Bp##INTERFACE(obj),其中INTERFACE就是我們的AudioPolicyService,
obj就是binder,所以展開返回的物件就是BpAudioPolicyService(binder)。

9.此時我們回到AudioSystem.cpp中
setStreamVolumeIndex

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

那麼此時呼叫的就是BpAudioPolicyService(binder)->setStreamVolumeIndex(stream, index, device)
而這個BpAudioPolicyService的定義在IAudioPolicyService.cpp中。

10.IAudioPolicyService.cpp

class BpAudioPolicyService : public BpInterface<IAudioPolicyService>
{
...

    virtual status_t setStreamVolumeIndex(audio_stream_type_t stream,
                                          int index,
                                          audio_devices_t device)
    {
        Parcel data, reply;
        //呼叫Parcel講介面描述符以及stream,index,device包裝進data
        data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
        data.writeInt32(static_cast <uint32_t>(stream));
        data.writeInt32(index);
        data.writeInt32(static_cast <uint32_t>(device));
        //使用transact將data以及SET_STREAM_VOLUME傳走,並且傳了一個reply的引用來儲存傳回來的值
        remote()->transact(SET_STREAM_VOLUME, data, &reply);
        return static_cast <status_t> (reply.readInt32());
    }

...
}

其中remote()是通過繼承關係BpAudioPolicyService -> BpInterface -> BpRefBase,在類BpRefBase中定義的

inline  IBinder*        remote()                { return mRemote; }
    IBinder* const          mRemote;

這裡是內聯的,並且return的mRemote也是const的,只賦值一次,它是在前面獲取遠端服務AudioPolicyService時候建立的BpBinder物件(主要是打開了binder驅動,獲得FD描述符,並且記憶體映射了空間),所以呼叫BpBinder.cpp的transact函式

11.BpBinder.cpp

status_t BpBinder::transact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
    // Once a binder has died, it will never come back to life.
    if (mAlive) {
        status_t status = IPCThreadState::self()->transact(
            mHandle, code, data, reply, flags);
        if (status == DEAD_OBJECT) mAlive = 0;
        return status;
    }

    return DEAD_OBJECT;
}

呼叫IPCThreadState.cpp的transact。

12.進入IPCThreadState.cpp

在這個IPCThreadState就是真正交換通訊的地方了,void IPCThreadState::joinThreadPool(bool isMain)會迴圈呼叫
result = getAndExecuteCommand();處理命令,而我們的IPCThreadState::self()->transact就會使用Pacle來封裝我們傳入的資料交給
joinThreadPool來處理。最終會在

status_t IPCThreadState::executeCommand(int32_t cmd)中呼叫
error = the_context_object->transact(tr.code, buffer, &reply, tr.flags);
這個the_context_object我們可以根據定義
sp the_context_object;瞭解這是一個bbinder物件(在binder.cpp中)。

13.進入binder.cpp

status_t BBinder::transact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
    data.setDataPosition(0);
    status_t err = NO_ERROR;
    switch (code) {
        case PING_TRANSACTION:
            reply->writeInt32(pingBinder());
            break;
        default:
            err = onTransact(code, data, reply, flags);
            break;
    }
    if (reply != NULL) {
        reply->setDataPosition(0);
    }
    return err;
}

這裡呼叫了err = onTransact(code, data, reply, flags);根據繼承關係,我們可以知道呼叫的是AudioPolicyService的ontransact方法。

14.AudioPolicyService.cpp

status_t AudioPolicyService::onTransact(
        uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
    return BnAudioPolicyService::onTransact(code, data, reply, flags);
}

所以現在我們知道應答了binder的transact之後其實是呼叫了AudioPolicyService中的 ontransact。

15.IAudioPolicyService

status_t BnAudioPolicyService::onTransact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
    ...................
    case SET_STREAM_VOLUME: {
            CHECK_INTERFACE(IAudioPolicyService, data, reply);
            audio_stream_type_t stream =
                    static_cast <audio_stream_type_t>(data.readInt32());
            int index = data.readInt32();
            audio_devices_t device = static_cast <audio_devices_t>(data.readInt32());
            reply->writeInt32(static_cast <uint32_t>(setStreamVolumeIndex(stream,
                                                                          index,
                                                                          device)));
            return NO_ERROR;
        } break;
     ......................

此處的reply->writeInt32(static_cast (setStreamVolumeIndex(stream,
index,device));
這裡呼叫了setStreamVolumeIndex方法,所以AudioPolicyService呼叫了BnAudioPolicyService::onTransact後回去呼叫自己的
setStreamVolumeIndex方法。而setStreamVolumeIndex的實現在android8.0中在AudioPolicyInterfaceImpl.cpp中。

16.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);
    return mAudioPolicyManager->setStreamVolumeIndex(stream,
                                                    index,
                                                    device);
}

這裡呼叫mAudioPolicyManager->setStreamVolumeIndex(stream, index,device);

AudioPolicyManager下的setStreamVolumeIndex定義在AudioPolicyManager.cpp中。

17.AudioPolicyManager.cpp

status_t AudioPolicyManager::setStreamVolumeIndex(audio_stream_type_t stream,
                                                  int index,
                                                  audio_devices_t device)
{
    if ((index < mVolumeCurves->getVolumeIndexMin(stream)) ||
            (index > mVolumeCurves->getVolumeIndexMax(stream))) {
        return BAD_VALUE;
    }
    if (!audio_is_output_device(device)) {
        return BAD_VALUE;
    }

    // Force max volume if stream cannot be muted
    if (!mVolumeCurves->canBeMuted(stream)) index = mVolumeCurves->getVolumeIndexMax(stream);

    // update other private stream volumes which follow this one
    for (int curStream = 0; curStream < AUDIO_STREAM_FOR_POLICY_CNT; curStream++) {
        if (!streamsMatchForvolume(stream, (audio_stream_type_t)curStream)) {
            continue;
        }
        mVolumeCurves->addCurrentVolumeIndex((audio_stream_type_t)curStream, device, index);
    }

    // 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 strategy corresponding to 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 strategy
    // - For default requested device (AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME), apply volume only if
    // no specific device volume value exists for currently selected device.
    status_t status = NO_ERROR;
    for (size_t i = 0; i < mOutputs.size(); i++) {
        sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
        audio_devices_t curDevice = Volume::getDeviceForVolume(desc->device());
        for (int curStream = 0; curStream < AUDIO_STREAM_FOR_POLICY_CNT; curStream++) {
            if (!streamsMatchForvolume(stream, (audio_stream_type_t)curStream)) {
                continue;
            }
            if (!(desc->isStreamActive((audio_stream_type_t)curStream) ||
                    (isInCall() && (curStream == AUDIO_STREAM_VOICE_CALL)))) {
                continue;
            }
            routing_strategy curStrategy = getStrategy((audio_stream_type_t)curStream);
            audio_devices_t curStreamDevice = getDeviceForStrategy(curStrategy, false /*fromCache*/);
            if ((device != AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME) &&
                    ((curStreamDevice & device) == 0)) {
                continue;
            }
            bool applyVolume;
            if (device != AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME) {
                curStreamDevice |= device;
                applyVolume = (curDevice & curStreamDevice) != 0;
            } else {
                applyVolume = !mVolumeCurves->hasVolumeIndexForDevice(
                        stream, Volume::getDeviceForVolume(curStreamDevice));
            }

            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((audio_stream_type_t)curStream, index, desc, curDevice,
                            (stream == AUDIO_STREAM_SYSTEM) ? TOUCH_SOUND_FIXED_DELAY_MS : 0);
                if (volStatus != NO_ERROR) {
                    status = volStatus;
                }
            }
        }
    }
    return NO_ERROR;
}

在這裡會在audiopolicymanager中做一系列的處理,最後調回AudioSystem再進入AudioFlinger中,由於在工作中用到的情況是在AudioPolicyManager::setStreamVolumeIndex(audio_stream_type_t stream,int index, audio_devices_t device)之後便直接切入自己的中介軟體了,所以沒有再進入安卓的流程,如果有需要的話可以再繼續往下研究。難點主要在於binder和JNI,其實只要瞭解了binder和JNI之後,更多的就是一些流程化的東西了。

相關推薦

Android音量設定流程android8.0

最近一直在解安卓audio部分的bug,其中最多的就是音量設定方面的問題,在這裡把自己學習到的一些東西記錄一下,以供參考。 安卓java部分的音量設定首先呼叫到AudioManager.java中 在這裡有兩種方法可以設定音量setStreamVolume和

Android進階3:Activity原始碼分析2 —— Activity啟動和銷燬流程8.0

上篇文章講述了app從啟動建立Activity呼叫onCreate,onStart, onResume方法,這篇文章講述一下Activity啟動的另一個切入點:startActivity方法,啟動Activity。 通過上一篇文章,我們總結一下: 1:A

Android音量設定流程乾貨版

1.     音量級數定義 在AudioService.java中定義了最大音量MAX_STREAM_VOLUME,手機的設定property可以覆蓋它。 2.     音量初始化 initStreamVolume傳入AudioPolicyManagerBase裡的Stre

Android Activity啟動流程(基於Android8.0系統)

主要物件介紹 ActivityManagerService:負責系統中所有Activity的生命週期; Activi

Android 一行程式碼版本更新適配到Android8.0

做Android 專案的時候一般都需要在App內版本更新,以前自己寫過,今天介紹的不是自己的,是一個開源,功能比較強大,一句話實現版本更新功能 一、依賴 compile 'com.allenliu.versionchecklib:library:2.0.5' 二、程式碼 AllenVer

Android系統啟動流程解析init進程啟動過程

option 寫入 android change failed miss 通知 target sna 前言 作為“Android框架層”這個大系列中的第一個系列,我們首先要了解的是Android系統啟動流程,在這個流程中會涉及到很多重要的知識點,這個系列我們就來一一講解它們

(Android) RadioButton設定setChecktrue無效

今天碰到個問題,RadioButton設定setCheck(true)無效,佈局xml是RadioGroup裡包含了幾個RadioButton。 經驗證,發現之前有個呼叫,把所有RadioButton都呼叫setChecked(false),這個會導致再次設定setCheched(true)無效

Android應用反編譯詳細流程Mac系統

新版Android應用反編譯詳細流程(Mac系統) 以前一直都是用win來反編譯,後來換了Mac就一直沒弄過了,今天剛好有需要,正好也做個筆記,留著以後備用。 其實現在大多數應用都會做一些防護,下面這種方式,只適用於一般的沒做加固處理的apk。 現在開始吧,首先你需要準備好必

《第一行程式碼》 第五章:全域性大喇叭 筆記基於Android8.0

由於Android8.0對廣播機制做了很大的調整理,導致《第一行程式碼》中很多例項無法正常執行,因此我結合書本,自行整理了一下。 廣播需要接收器和傳送器。系統的動作都會發送一條廣播,例如電量的變化,系

Android Multimedia框架總結十二CodeC部分之OMXCodec與OMX事件回撥流程

前言:上篇文中分析到AwesomePlayer到OMX服務,曾介紹到,OMX服務主要完成三個任務: NodeInstance列表的管理,NodeInstance的操作, 事件的處理。最後這個事件處理就是今天放大看的內容。要一步一步一Codec,事件傳遞必不可

Android系統啟動流程解析init程序啟動過程

前言 作為“Android框架層”這個大系列中的第一個系列,我們首先要了解的是Android系統啟動流程,在這個流程中會涉及到很多重要的知識點,這個系列我們就來一一講解它們,這一篇我們就來學習init程序。 1.init簡介 init程序是An

Android 測試的流程工作流程

•5、等待開發提交測試版本,提交後優先執行冒煙測試。冒煙測試的結果,需要郵件周知相關人,開發,測試,產品,其中重要的是開發領導,測試領導和產品。冒煙不通過等待開發重新提交版本,冒煙通過了進入執行用例進行測試階段。

Feign的超時與重試設定SpringCloud2.0

1.Feign的依賴 <dependency> <groupId>org.springframework.cloud</groupId> <artif

Android原始碼解析之十一-->應用程序啟動流程

本節主要是通過分析Activity的啟動過程介紹應用程式程序的啟動流程。關於Android的應用程序在android guide中有這樣的一段描述: By default, every application runs in its own Linu

Android系統啟動流程解析Zygote程序啟動過程

前言 上一篇文章我們分析了init程序的啟動過程,啟動過程中主要做了三件事,其中一件就是建立了Zygote程序,那麼Zygote程序是什麼,它做了哪些事呢?這篇文章會給你這些問題的答案。 1.Zygote簡介 在Android系統中,DVM(D

0開始設定django基於CentOS7

一 CentOS python3的安裝 yum -y groupinstall "Development tools" yum -y install zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel

Android圖表控制元件MPAndroidChart的簡單介紹MPAndroidChart3.0

每個類對應的圖是什麼github上有詳細的介紹圖表類具有相同的地方X軸:XAxisY軸:YAxis圖例:Legend描述:Description限制線:LimitLine選中圖表中的值,可顯示的檢視:MarkerView 具體在圖表中的表現如下圖以曲線圖為例依賴:projec

[RK3288][Android6.0] Audio的音量設定流程小結

Platform: Rockchip OS: Android 6.0 Kernel: 3.10.92 說明一:  AudioManager提供了兩個調節音量介面 adjustSuggestedSt

Android系統啟動流程Launcher啟動過程與系統啟動流程

相關文章  Android系統架構與系統原始碼目錄  Android系統啟動流程(一)解析init程序啟動過程  Android系統啟動流程(二)解析Zygote程序啟動過程  Android系統啟動流程(三)解析SyetemServer程序啟動過程 前言

Android系統啟動流程解析SyetemServer程序啟動過程

相關文章  Android系統架構與系統原始碼目錄  Android系統啟動流程(一)解析init程序啟動過程  Android系統啟動流程(二)解析Zygote程序啟動過程 前言 上一篇我們學習了Zygote程序,並且知道Zygote程序啟動了SyetemServ