天天看點

android 音量調節流程

 Audio音量調節是一級一級調節,而且分不同的流類型,如響鈴,通話,多媒體等。不同的裝置(藍牙裝置)的設定方法有所差別。

sdk的api,設定相應流的音量。不同的流index的範圍不一樣

//--->frameworks/base/media/java/android/media/AudioManager.java

public void setStreamVolume(int streamType, int index, int flags) {

    IAudioService service = getService();

    try {

        service.setStreamVolume(streamType, index, flags, 

            getContext().getOpPackageName());

    } catch (RemoteException e) {

        Log.e(TAG, "Dead object in setStreamVolume", e);

    }

}

java層Service實作,volume的調節的實作是用state模式來實作,可能需要原子性或不同的模式下調節音量的操作不同。

//--->frameworks/base/services/core/java/com/android/server/audio/AudioService.java

private void setStreamVolume(int streamType, int index, int flags, 

    String callingPackage,String caller, int uid) {

    ...(檢查參數)

    ...(轉換參數)

    // 擷取裝置

    final int device = getDeviceForStream(streamType);

    ...(特殊處理a2dp)

    ...(檢查uid,實體按鍵調節音量需要判斷目前使用者?)

    synchronized (mSafeMediaVolumeState) {

        mPendingVolumeCommand = null;

        oldIndex = streamState.getIndex(device);

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

        ...(特殊處理a2dp)

        ...(特殊處理HDMI)

        ...(設定一些标志位,如标記一些不可調節音量的裝置)

        //檢查目前是否可設定音量

        if (!checkSafeMediaVolume(streamTypeAlias, index, device)) {

            // 不可以則生成PendingCommand,等待合适的時機

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

    ...(判斷音量是否為0,調節模式(靜音或響鈴))

    mStreamStates[stream].mute(index == 0);

}

private void setStreamVolumeInt(int streamType,int index,int device,

    boolean force,String caller) {

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

    }

}

  @Override

public void handleMessage(Message msg) {

    ...

    switch (msg.what) {

        case MSG_SET_DEVICE_VOLUME:

            setDeviceVolume((VolumeStreamState) msg.obj, msg.arg1);

            break;

        ...

    }

    ...

}

private void setDeviceVolume(VolumeStreamState streamState, int device) {

    synchronized (VolumeStreamState.class) {

        // 設定音量

        streamState.applyDeviceVolume_syncVSS(device);

        ...(Apply change to all streams using this one as alias)

    }

    // Post a persist volume msg

    sendMsg(mAudioHandler,MSG_PERSIST_VOLUME,SENDMSG_QUEUE,device,0,

        streamState,PERSIST_DELAY);

}

public void applyDeviceVolume_syncVSS(int device) {

    int index;

    if (mIsMuted) {

        index = 0;

    } else if (((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 

        && mAvrcpAbsVolSupported) || ((device & mFullVolumeDevices) != 0)) {

        index = (mIndexMax + 5)/10;

    } else {

        index = (getIndex(device) + 5)/10;

    }

    AudioSystem.setStreamVolumeIndex(mStreamType, index, device);

}

AudioSystem的setStreamVolumeIndex是個native函數,從這裡到跳到c++代碼

//--->frameworks/base/media/java/android/media/AudioSystem.java

public static native int setStreamVolumeIndex(int stream, int index,

    int device);

1

2

3

jni的代碼沒做處理,直接轉發給c++層的AudioSystem

//--->frameworks/base/core/jni/android_media_AudioSystem.cpp

static JNINativeMethod gMethods[] = { ...

 {"setStreamVolumeIndex","(III)I",   (void *)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又踢給AudioPolicyService(這裡是binder通信,從這裡跳到服務端處理)

//--->frameworks/av/media/libmedia/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做了些權限和參數檢查,轉發給AudioPolicyManager

//---frameworks/av/services/audiopolicy/service/AudioPolicyService.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);

}

AudioPolicyManager的處理比較複雜,主要是包括了音頻政策的判斷

//--->frameworks/av/services/audiopolicy/managerdefault/AudioPolicyManager.cpp

status_t AudioPolicyManager::setStreamVolumeIndex(audio_stream_type_t stream,

    int index,audio_devices_t device)

{

    ...(檢查音量及裝置是否為audio裝置)

    ...(政策判斷)

    if ((device != AUDIO_DEVICE_OUT_DEFAULT) && 

        (device & (strategyDevice | accessibilityDevice)) == 0) {

        return NO_ERROR;

    }

    ...(設定每個輸出裝置的音量)

    status_t volStatus = checkAndSetVolume(stream, index, desc, curDevice);

    ...

}

status_t AudioPolicyManager::checkAndSetVolume(audio_stream_type_t stream,int index,

    const sp<AudioOutputDescriptor>& outputDesc,audio_devices_t device,int delayMs,bool force)

{

    ...(do not change actual stream volume if the stream is muted)

    ...(do not change in call volume if bluetooth is connected and vice versa)

    // 聲音等級與真正參數的轉換

    float volumeDb = computeVolume(stream, index, device);  

    // 設定輸出裝置的聲音

    outputDesc->setVolume(volumeDb, stream, device, delayMs, force);

    // 設定通話的音量??

    if (stream == AUDIO_STREAM_VOICE_CALL || stream == AUDIO_STREAM_BLUETOOTH_SCO) {

            ...

            mpClientInterface->setVoiceVolume(voiceVolume, delayMs);

            ...

        }

    }

    return NO_ERROR;

}

AudioOutputDescriptor是音頻裝置描述符,outputDesc是SwAudioOutputDescriptor類型。

//--->/frameworks/av/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp

 bool AudioOutputDescriptor::setVolume(float volume,audio_stream_type_t stream,

    audio_devices_t device __unused,uint32_t delayMs,bool force)

{

    // We actually change the volume if:

    // - the float value returned by computeVolume() changed

    // - the force flag is set

    if (volume != mCurVolume[stream] || force) {

        ALOGV("setVolume() for stream %d, volume %f, delay %d", stream, volume, delayMs);

        mCurVolume[stream] = volume;

        return true;

    }

    return false;

}

bool SwAudioOutputDescriptor::setVolume(float volume,audio_stream_type_t stream,

    audio_devices_t device,uint32_t delayMs,bool force)

{

    bool changed = AudioOutputDescriptor::setVolume(volume, stream, device, 

        delayMs, force);

    if (changed) {

        // Force VOICE_CALL to track BLUETOOTH_SCO stream volume when bluetooth audio is

        // enabled

        float volume = Volume::DbToAmpl(mCurVolume[stream]);

        if (stream == AUDIO_STREAM_BLUETOOTH_SCO) {

            mClientInterface->setStreamVolume(AUDIO_STREAM_VOICE_CALL, volume,

                mIoHandle, delayMs);

        }

        mClientInterface->setStreamVolume(stream, volume, mIoHandle, delayMs);

    }

    return changed;

}

AudioOutputDescriptor的mClientInterface是AudioPolicyService,是以會轉到AudioPolicyService的setStreamVolume 

AudioPolicyService異步執行這個操作,最後會轉到AudioSystem的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;

        ...

    }

}

AudioSystem又轉到AudioFlinger

//--->frameworks/av/media/libmedia/AudioSystem.cpp 

status_t AudioSystem::setStreamVolume(audio_stream_type_t stream, float value,

    audio_io_handle_t output)

{

    ...(權限參數檢查)

    af->setStreamVolume(stream, value, output);

    return NO_ERROR;

}

AudioFlinger會去擷取output對應的PlaybackThread并設定PlaybackThread的音量,如果output == AUDIO_IO_HANDLE_NONE,則設定所有PlaybackThread的音量。

//--->frameworks/av/services/audioflinger/AudioFlinger.cpp

status_t AudioFlinger::setStreamVolume(audio_stream_type_t stream, float value,

        audio_io_handle_t output)

{

    ...(權限檢查)

    ...(流類型檢查)

    AutoMutex lock(mLock);

    ...(擷取對應裝置的PlaybackTread)

    // ???

    mStreamTypes[stream].volume = value;

    if (thread == NULL) {   // output == AUDIO_IO_HANDLE_NONE

        for (size_t i = 0; i < mPlaybackThreads.size(); i++) {

            mPlaybackThreads.valueAt(i)->setStreamVolume(stream, value);

        }

    } else {

        thread->setStreamVolume(stream, value);

    }

    return NO_ERROR;

}

PlaybackThread設定mStreamTypes的volume。并喚醒PlaybackThread線程

void AudioFlinger::PlaybackThread::setStreamVolume(audio_stream_type_t stream, float value)

{

    Mutex::Autolock _l(mLock);

    mStreamTypes[stream].volume = value;

    broadcast_l();

}

不同類型的Thread貌似有不同使用方法 MixerThread是在prepareTracks_l裡使用,最後會設定AudioMixer的參數

//--->frameworks/av/services/audioflinger/Threads.cpp

AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTracks_l(

    Vector< sp<Track> > *tracksToRemove) {

    ...

    // FastTrack

    track->mCachedVolume = masterVolume * mStreamTypes[track->streamType()].volume;

    ...

    // NormalTrack

    // 這裡涉及到了左右聲道的音量的計算

    // compute volume for this track

    uint32_t vl, vr;       // in U8.24 integer format

    float vlf, vrf, vaf;   // in [0.0, 1.0] float format

    float typeVolume = mStreamTypes[track->streamType()].volume;

    float v = masterVolume * typeVolume;

    ...

    //計算完設定混音器的參數

    mAudioMixer->setParameter(name, param, AudioMixer::VOLUME0, &vlf);

    mAudioMixer->setParameter(name, param, AudioMixer::VOLUME1, &vrf);

    mAudioMixer->setParameter(name, param, AudioMixer::AUXLEVEL, &vaf);

    ...

}

// 最後會調用到mAudioMixer的setVolumeRampVariables

static inline bool setVolumeRampVariables(float newVolume, int32_t ramp,

    int16_t *pIntSetVolume, int32_t *pIntPrevVolume, int32_t *pIntVolumeInc,

    float *pSetVolume, float *pPrevVolume, float *pVolumeInc){...}

DirectOutputThread在processVolume_l裡使用(processVolume_l在prepareTracks_l中被調用) 

processVolume_l直接設定了輸出裝置的volume

//--->frameworks/av/services/audioflinger/Threads.cpp   

void AudioFlinger::DirectOutputThread::processVolume_l(Track *track, bool lastTrack) {

    ...

    float typeVolume = mStreamTypes[track->streamType()].volume;

    float v = mMasterVolume * typeVolume;

    ...(一系列的設定)

    if (mOutput->stream->set_volume) {

        mOutput->stream->set_volume(mOutput->stream, left, right);

    }

}

轉載位址:https://blog.csdn.net/axlecho/article/details/78510496