Android Audio音量設置流程



轉載自http://blog.axlecho.com/audioyin-liang-she-zhi-liu-cheng/

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

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 == AUDIOIOHANDLE_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在processVolumel裏使用(processVolumel在prepareTracksl中被調用)
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);
    }
}

還有其他的幾種Thread都是上面兩種Thread的子類,處理方式是一致的

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章