Android Audio代碼分析26 – Audio Strategy – Android移動開發技術文章_手機開發 Android移動開發教學課程

在看示例代碼 testPlaybackHeadPositionIncrease 的時候,我們對 play 函數進行瞭研究。
不過,當時對 Android 中聲音競爭策略相關的內容,並沒有詳細分析。
今天就以 AudioTrack 的播放為引子,來仔細看看 Anroid 中各種聲音是以什麼樣的策略來競爭的。


從 Java 側類 AudioTrack 的 play 函數到函數 AudioFlinger::PlaybackThread::Track::start 之間的調用關系就不再敘述瞭。
在看示例代碼 testPlaybackHeadPositionIncrease 的時候已經說明過瞭。
今天就從函數 AudioFlinger::PlaybackThread::Track::start 開始分析。


*****************************************源碼*************************************************
status_t AudioFlinger::PlaybackThread::Track::start()
{
    status_t status = NO_ERROR;
    LOGV("start(%d), calling thread %d session %d",
            mName, IPCThreadState::self()->getCallingPid(), mSessionId);
    sp<ThreadBase> thread = mThread.promote();
    if (thread != 0) {
        Mutex::Autolock _l(thread->mLock);
        int state = mState;
        // here the track could be either new, or restarted
        // in both cases "unstop" the track
        if (mState == PAUSED) {
            mState = TrackBase::RESUMING;
            LOGV("PAUSED => RESUMING (%d) on thread %p", mName, this);
        } else {
            mState = TrackBase::ACTIVE;
            LOGV("? => ACTIVE (%d) on thread %p", mName, this);
        }


        if (!isOutputTrack() && state != ACTIVE && state != RESUMING) {
            thread->mLock.unlock();
            status = AudioSystem::startOutput(thread->id(),
                                              (AudioSystem::stream_type)mStreamType,
                                              mSessionId);
            thread->mLock.lock();
        }
        if (status == NO_ERROR) {
            PlaybackThread *playbackThread = (PlaybackThread *)thread.get();
            playbackThread->addTrack_l(this);
        } else {
            mState = state;
        }
    } else {
        status = BAD_VALUE;
    }
    return status;
}
**********************************************************************************************
源碼路徑:
frameworks\base\services\AudioFlinger.cpp


#######################說明################################
status_t AudioFlinger::PlaybackThread::Track::start()
{
    status_t status = NO_ERROR;
    LOGV("start(%d), calling thread %d session %d",
            mName, IPCThreadState::self()->getCallingPid(), mSessionId);
    sp<ThreadBase> thread = mThread.promote();
    if (thread != 0) {
        Mutex::Autolock _l(thread->mLock);
        int state = mState;
        // here the track could be either new, or restarted
        // in both cases "unstop" the track
        if (mState == PAUSED) {
            mState = TrackBase::RESUMING;
            LOGV("PAUSED => RESUMING (%d) on thread %p", mName, this);
        } else {
            mState = TrackBase::ACTIVE;
            LOGV("? => ACTIVE (%d) on thread %p", mName, this);
        }


        if (!isOutputTrack() && state != ACTIVE && state != RESUMING) {
            thread->mLock.unlock();
            status = AudioSystem::startOutput(thread->id(),
                                              (AudioSystem::stream_type)mStreamType,
                                              mSessionId);
++++++++++++++++++++++++++++AudioSystem::startOutput++++++++++++++++++++++++++++++++++++
從函數 AudioFlinger::PlaybackThread::Track::start 進入:
status_t AudioSystem::startOutput(audio_io_handle_t output,
                                  AudioSystem::stream_type stream,
                                  int session)
{
    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
    if (aps == 0) return PERMISSION_DENIED;
    return aps->startOutput(output, stream, session);
+++++++++++++++++++++++++++++AudioPolicyService::startOutput+++++++++++++++++++++++++++++++++++
從函數 AudioSystem::startOutput 進入:
status_t AudioPolicyService::startOutput(audio_io_handle_t output,
                                         AudioSystem::stream_type stream,
                                         int session)
{
    if (mpPolicyManager == NULL) {
        return NO_INIT;
    }
    LOGV("startOutput() tid %d", gettid());
    Mutex::Autolock _l(mLock);
    return mpPolicyManager->startOutput(output, stream, session);
+++++++++++++++++++++++++++++AudioPolicyManagerBase::startOutput+++++++++++++++++++++++++++++++++++
從函數 AudioPolicyService::startOutput 進入:
// 主要的處理是從這兒開始的


status_t AudioPolicyManagerBase::startOutput(audio_io_handle_t output,
                                             AudioSystem::stream_type stream,
                                             int session)
{
    LOGV("startOutput() output %d, stream %d, session %d", output, stream, session);
    ssize_t index = mOutputs.indexOfKey(output);
    if (index < 0) {
        LOGW("startOutput() unknow output %d", output);
        return BAD_VALUE;
    }


    AudioOutputDescriptor *outputDesc = mOutputs.valueAt(index);
// 函數 getStrategy 就是根據 stream type 返回特定的 strategy
    routing_strategy strategy = getStrategy((AudioSystem::stream_type)stream);
++++++++++++++++++++++++++++AudioPolicyManagerBase::getStrategy++++++++++++++++++++++++++++++++++++
從函數 AudioPolicyManagerBase::startOutput 進入:


本來不打算列出該函數,不過,看到後面關於 strategy 優先級的時候,發現需要知道每種策略分別是用來幹嗎的。
所以首先要知道策略對應的 stream type ,
AudioPolicyManagerBase::routing_strategy AudioPolicyManagerBase::getStrategy(
        AudioSystem::stream_type stream) {
    // stream to strategy mapping
    switch (stream) {
    case AudioSystem::VOICE_CALL: // 電話來瞭
    case AudioSystem::BLUETOOTH_SCO: // 藍牙耳機接通瞭
        return STRATEGY_PHONE;
    case AudioSystem::RING: // 鈴聲響瞭
    case AudioSystem::NOTIFICATION: // 通知,例如界面中最上面一欄中有消息瞭
    case AudioSystem::ALARM: // 警告,電池沒電時的警告?
    case AudioSystem::ENFORCED_AUDIBLE:
        return STRATEGY_SONIFICATION;
    case AudioSystem::DTMF: // 可參考鏈接:http://baike.baidu.com/view/171916.htm
        return STRATEGY_DTMF;
    default:
        LOGE("unknown stream type");
    case AudioSystem::SYSTEM: // 系統聲音采用 media strategy, 例如,如果正在播放音樂的時候按鍵,
// mute 掉音樂,並切換 output 的話,將導致 很差的用戶體驗。
// 其中可以得到以下信息:
// 1、按鍵聲音屬於 system stream type 。
// 2、策略的改變將會導致 output 的切換
// 3、優先級高的策略 start 時會 mute 掉優先級低的策略
        // NOTE: SYSTEM stream uses MEDIA strategy because muting music and switching outputs
        // while key clicks are played produces a poor result
    case AudioSystem::TTS: // TTS 就是 Text To Speech
    case AudioSystem::MUSIC:
        return STRATEGY_MEDIA;
    }
}
返回到函數 AudioPolicyManagerBase::startOutput
—————————-AudioPolicyManagerBase::getStrategy————————————


#ifdef WITH_A2DP
    if (mA2dpOutput != 0  && !a2dpUsedForSonification() && strategy == STRATEGY_SONIFICATION) {
        setStrategyMute(STRATEGY_MEDIA, true, mA2dpOutput);
    }
#endif


    // incremenent usage count for this stream on the requested output:
    // NOTE that the usage count is the same for duplicated output and hardware output which is
    // necassary for a correct control of hardware output routing by startOutput() and stopOutput()
// 增加請求的 output 上該 stream 的使用計數
// 註意: duplicated output 和 hardware output 中的使用計數是相同的。
// 因為這對通過 startOutput() 函數和 stopOutput() 函數正確地控制 hardware output routing 是必要的。
    outputDesc->changeRefCount(stream, 1);
++++++++++++++++++++++++++++AudioPolicyManagerBase::AudioOutputDescriptor::changeRefCount++++++++++++++++++++++++++++++++++++
從函數 AudioPolicyManagerBase::startOutput 進入:
void AudioPolicyManagerBase::AudioOutputDescriptor::changeRefCount(AudioSystem::stream_type stream, int delta)
{
    // forward usage count change to attached outputs
// 如果是 duplicated 的,需要改變它所包含的兩個 output 中的使用計數。
    if (isDuplicated()) {
        mOutput1->changeRefCount(stream, delta);
        mOutput2->changeRefCount(stream, delta);
    }
    if ((delta + (int)mRefCount[stream]) < 0) {
        LOGW("changeRefCount() invalid delta %d for stream %d, refCount %d", delta, stream, mRefCount[stream]);
        mRefCount[stream] = 0;
        return;
    }
    mRefCount[stream] += delta;
    LOGV("changeRefCount() stream %d, count %d", stream, mRefCount[stream]);
}
返回到函數 AudioPolicyManagerBase::startOutput
—————————-AudioPolicyManagerBase::AudioOutputDescriptor::changeRefCount————————————


    setOutputDevice(output, getNewDevice(output));
++++++++++++++++++++++++++++AudioPolicyManagerBase::getNewDevice++++++++++++++++++++++++++++++++++++
從函數 AudioPolicyManagerBase::startOutput 進入:
uint32_t AudioPolicyManagerBase::getNewDevice(audio_io_handle_t output, bool fromCache)
{
    uint32_t device = 0;


    AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output);
    // check the following by order of priority to request a routing change if necessary:
    // 1: we are in call or the strategy phone is active on the hardware output:
    //      use device for strategy phone
    // 2: the strategy sonification is active on the hardware output:
    //      use device for strategy sonification
    // 3: the strategy media is active on the hardware output:
    //      use device for strategy media
    // 4: the strategy DTMF is active on the hardware output:
    //      use device for strategy DTMF
// 根據以下的優先級順序,來檢查必要的路線改變
// 1、如果來電話瞭,或者 hardware output 中的 strategy phone 是活動的,
//    則使用 phone strategy 。
//    有兩種情況會使用到 strategy phone ,來電話瞭和藍牙耳機接通瞭。
// 2、如果 hardware output 中的 strategy sonification 是活動的,
//    則使用 strategy sonification .
//    有四種情況會使用 stratety sonification ,來電鈴聲,通知,警告,
//    和是 ENFORCED_AUDIBLE stream 的時候。
// 3、如果 hardware output 中的 strategy media 是活動的,
//    則使用 strategy media .
//    Media 播放, 系統聲音和 TTS 會使用 media 策略。
// 4、如果 hardware output 中的 strategy DTMF 是活動的,
//    則使用 strategy DTMF .
//    在 stream type 是 DTMF 的時候會使用 DTMF 策略。
//    關於 DTMF 請參考 http://baike.baidu.com/view/171916.htm
    if (isInCall() ||
        outputDesc->isUsedByStrategy(STRATEGY_PHONE)) {
// bool isUsedByStrategy(routing_strategy strategy) { return (strategyRefCount(strategy) != 0);}
+++++++++++++++++++++++++++AudioPolicyManagerBase::AudioOutputDescriptor::strategyRefCount+++++++++++++++++++++++++++++++++++++
從函數 AudioPolicyManagerBase::getNewDevice 進入:
// 檢查 output 中是否使用瞭指定的 strategy
uint32_t AudioPolicyManagerBase::AudioOutputDescriptor::strategyRefCount(routing_strategy strategy)
{
    uint32_t refCount = 0;
    for (int i = 0; i < (int)AudioSystem::NUM_STREAM_TYPES; i++) {
        if (getStrategy((AudioSystem::stream_type)i) == strategy) {
            refCount += mRefCount[i];
        }
    }
    return refCount;
}
返回到函數 AudioPolicyManagerBase::getNewDevice
—————————AudioPolicyManagerBase::AudioOutputDescriptor::strategyRefCount————————————-
        device = getDeviceForStrategy(STRATEGY_PHONE, fromCache);
    } else if (outputDesc->isUsedByStrategy(STRATEGY_SONIFICATION)) {
        device = getDeviceForStrategy(STRATEGY_SONIFICATION, fromCache);
    } else if (outputDesc->isUsedByStrategy(STRATEGY_MEDIA)) {
        device = getDeviceForStrategy(STRATEGY_MEDIA, fromCache);
    } else if (outputDesc->isUsedByStrategy(STRATEGY_DTMF)) {
        device = getDeviceForStrategy(STRATEGY_DTMF, fromCache);
    }
++++++++++++++++++++++++++++AudioPolicyManagerBase::isInCall++++++++++++++++++++++++++++++++++++
從函數 AudioPolicyManagerBase::getNewDevice 進入:
bool AudioPolicyManagerBase::isInCall()
{
// 函數 AudioPolicyManagerBase::setPhoneState 中會改變 mPhoneState 的值


// 調用關系:android_media_AudioSystem_setPhoneState
// 調用 AudioSystem::setPhoneState
// 調用 AudioPolicyService::setPhoneState
// 調用 AudioPolicyManagerBase::setPhoneState


    return isStateInCall(mPhoneState);
++++++++++++++++++++++++++++AudioPolicyManagerBase::isStateInCall++++++++++++++++++++++++++++++++++++
從函數 AudioPolicyManagerBase::isInCall 進入:
bool AudioPolicyManagerBase::isStateInCall(int state) {
    return ((state == AudioSystem::MODE_IN_CALL) ||
            (state == AudioSystem::MODE_IN_COMMUNICATION));
+++++++++++++++++++++++++++++audio_mode+++++++++++++++++++++++++++++++++++
從函數 AudioPolicyManagerBase::isStateInCall 進入:
    enum audio_mode {
        MODE_INVALID = -2,
        MODE_CURRENT = -1,
        MODE_NORMAL = 0,
        MODE_RINGTONE,
        MODE_IN_CALL,
        MODE_IN_COMMUNICATION,
        NUM_MODES  // not a valid entry, denotes end-of-list
    };
返回到函數 AudioPolicyManagerBase::isStateInCall
—————————–audio_mode———————————–
}
返回到函數 AudioPolicyManagerBase::isInCall
—————————-AudioPolicyManagerBase::isStateInCall————————————
}
返回到函數 AudioPolicyManagerBase::getNewDevice
—————————-AudioPolicyManagerBase::isInCall————————————


+++++++++++++++++++++++++++AudioPolicyManagerBase::getDeviceForStrategy+++++++++++++++++++++++++++++++++++++
從函數 AudioPolicyManagerBase::getNewDevice 進入:
uint32_t AudioPolicyManagerBase::getDeviceForStrategy(routing_strategy strategy, bool fromCache)
{
    uint32_t device = 0;


    if (fromCache) {
        LOGV("getDeviceForStrategy() from cache strategy %d, device %x", strategy, mDeviceForStrategy[strategy]);
        return mDeviceForStrategy[strategy];
    }


    switch (strategy) {
    case STRATEGY_DTMF:
        if (!isInCall()) {
// 不是打電話過來或者在通話中的話,DTMF strategy 和 MEDIA strategy 規則一樣
            // when off call, DTMF strategy follows the same rules as MEDIA strategy
            device = getDeviceForStrategy(STRATEGY_MEDIA, false);
            break;
        }
// 有電話打過來,或者在通話中的話, DTMF strategy 和 PHONE strategy 規則一致
        // when in call, DTMF and PHONE strategies follow the same rules
        // FALL THROUGH


    case STRATEGY_PHONE:
// 對於 PHONE strategy , 首先判斷是否強制要求使用瞭什麼設備,然後再根據優先級順序,尋找可用的 device
        // for phone strategy, we first consider the forced use and then the available devices by order
        // of priority
        switch (mForceUse[AudioSystem::FOR_COMMUNICATION]) {
        case AudioSystem::FORCE_BT_SCO:
            if (!isInCall() || strategy != STRATEGY_DTMF) {
// 不是上述兩種情況的話,肯定是outputDesc->isUsedByStrategy(STRATEGY_PHONE)作為條件走到這一步的
                device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
                if (device) break;
            }
            device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
            if (device) break;
            device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO;
            if (device) break;
// 如果請求瞭 SCO device ,但是沒有 SCO device 可用,則進入 default case
            // if SCO device is requested but no SCO device is available, fall back to default case
            // FALL THROUGH


        default:    // FORCE_NONE
            device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE;
            if (device) break;
            device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADSET;
            if (device) break;
#ifdef WITH_A2DP
            // when not in a phone call, phone strategy should route STREAM_VOICE_CALL to A2DP
            if (!isInCall()) {
                device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP;
                if (device) break;
                device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES;
                if (device) break;
            }
#endif
            device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_EARPIECE;
            if (device == 0) {
                LOGE("getDeviceForStrategy() earpiece device not found");
            }
            break;


        case AudioSystem::FORCE_SPEAKER:
            if (!isInCall() || strategy != STRATEGY_DTMF) {
                device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
                if (device) break;
            }
#ifdef WITH_A2DP
            // when not in a phone call, phone strategy should route STREAM_VOICE_CALL to
            // A2DP speaker when forcing to speaker output
            if (!isInCall()) {
                device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER;
                if (device) break;
            }
#endif
            device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_SPEAKER;
            if (device == 0) {
                LOGE("getDeviceForStrategy() speaker device not found");
            }
            break;
        }
    break;


    case STRATEGY_SONIFICATION:


        // If incall, just select the STRATEGY_PHONE device: The rest of the behavior is handled by
        // handleIncallSonification().
        if (isInCall()) {
            device = getDeviceForStrategy(STRATEGY_PHONE, false);
            break;
        }
        device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_SPEAKER;
        if (device == 0) {
            LOGE("getDeviceForStrategy() speaker device not found");
        }
        // The second device used for sonification is the same as the device used by media strategy
        // FALL THROUGH


    case STRATEGY_MEDIA: {
        uint32_t device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_AUX_DIGITAL;
 
        if (device2 == 0) {
            device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_WIRED_HDMI;
        }
        if (device2 == 0) {
            device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE;
        }
        if (device2 == 0) {
            device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADSET;
        }
#ifdef WITH_A2DP
        if (mA2dpOutput != 0) {
            if (strategy == STRATEGY_SONIFICATION && !a2dpUsedForSonification()) {
                break;
            }
            if (device2 == 0) {
                device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP;
            }
            if (device2 == 0) {
                device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES;
            }
            if (device2 == 0) {
                device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER;
            }
        }
#endif
        if (device2 == 0) {
            device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_SPEAKER;
        }


        // device is DEVICE_OUT_SPEAKER if we come from case STRATEGY_SONIFICATION, 0 otherwise
        device |= device2;
        if (device == 0) {
            LOGE("getDeviceForStrategy() speaker device not found");
        }
        } break;


    default:
        LOGW("getDeviceForStrategy() unknown strategy: %d", strategy);
        break;
    }


    LOGV("getDeviceForStrategy() strategy %d, device %x", strategy, device);
    return device;
}
返回到函數 AudioPolicyManagerBase::getNewDevice
—————————AudioPolicyManagerBase::getDeviceForStrategy————————————-


    LOGV("getNewDevice() selected device %x", device);
    return device;
}
返回到函數 AudioPolicyManagerBase::startOutput
—————————-AudioPolicyManagerBase::getNewDevice————————————
++++++++++++++++++++++++++++AudioPolicyManagerBase::setOutputDevice++++++++++++++++++++++++++++++++++++
從函數 AudioPolicyManagerBase::startOutput 進入
void AudioPolicyManagerBase::setOutputDevice(audio_io_handle_t output, uint32_t device, bool force, int delayMs)
{
    LOGV("setOutputDevice() output %d device %x delayMs %d", output, device, delayMs);
    AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output);

 


// 如果 output 是 duplicated 的,直接去處理其包含的兩個 output
    if (outputDesc->isDuplicated()) {
        setOutputDevice(outputDesc->mOutput1->mId, device, force, delayMs);
        setOutputDevice(outputDesc->mOutput2->mId, device, force, delayMs);
        return;
    }
#ifdef WITH_A2DP
    // filter devices according to output selected
    if (output == m A2dpOutput) {
        device &= AudioSystem::DEVICE_OUT_ALL_A2DP;
    } else {
        device &= ~AudioSystem::DEVICE_OUT_ALL_A2DP;
    }
#endif


    uint32_t prevDevice = (uint32_t)outputDesc->device();
    // Do not change the routing if:
    //  – the requestede device is 0
    //  – the requested device is the same as current device and force is not specified.
    // Doing this check here allows the caller to call setOutputDevice() without conditions
    if ((device == 0 || device == prevDevice) && !force) {
        LOGV("setOutputDevice() setting same device %x or null device for output %d", device, output);
        return;
    }


// 修改 output 中的 current device
    outputDesc->mDevice = device;
    // mute media streams if both speaker and headset are selected
    if (output == mHardwareOutput && AudioSystem::popCount(device) == 2) {
        setStrategyMute(STRATEGY_MEDIA, true, output);
++++++++++++++++++++++++++AudioPolicyManagerBase::setStrategyMute++++++++++++++++++++++++++++++++++++++
從函數 AudioPolicyManagerBase::setOutputDevice 進入
// mute 掉指定 strategy 對應的所有 stream
void AudioPolicyManagerBase::setStrategyMute(routing_strategy strategy, bool on, audio_io_handle_t output, int delayMs)
{
    LOGV("setStrategyMute() strategy %d, mute %d, output %d", strategy, on, output);
    for (int stream = 0; stream < AudioSystem::NUM_STREAM_TYPES; stream++) {
        if (getStrategy((AudioSystem::stream_type)stream) == strategy) {
            setStreamMute(stream, on, output, delayMs);
+++++++++++++++++++++++++++AudioPolicyManagerBase::setStreamMute+++++++++++++++++++++++++++++++++++++
從函數 AudioPolicyManagerBase::setStrategyMute 進入
void AudioPolicyManagerBase::setStreamMute(int stream, bool on, audio_io_handle_t output, int delayMs)
{
    StreamDescriptor &streamDesc = mStreams[stream];
    AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output);


    LOGV("setStreamMute() stream %d, mute %d, output %d, mMuteCount %d", stream, on, output, outputDesc->mMuteCount[stream]);


    if (on) {
        if (outputDesc->mMuteCount[stream] == 0) {
// 如果該 stream 還沒有 mute 過,則對其進行 mute
            if (streamDesc.mCanBeMuted) {
// mute 其實就是將 stream 的音量設置為 0
// checkAndSetVolume 函數在此處就先不看瞭,等到下面看音量設置的時候在分析
                checkAndSetVolume(stream, 0, output, outputDesc->device(), delayMs);
            }
        }
        // increment mMuteCount after calling checkAndSetVolume() so that volume change is not ignored
// 將 mute 計數加1,以防止聲音改變被忽略
        outputDesc->mMuteCount[stream]++;
    } else {
        if (outputDesc->mMuteCount[stream] == 0) {
// 如果 mute 計數為0,不進行任何操作
            LOGW("setStreamMute() unmuting non muted stream!");
            return;
        }
        if (–outputDesc->mMuteCount[stream] == 0) {
// mute 計數減1,若 mute 計數變為0,則將 stream 變為 mute off
// 也就是恢復 stream 的音量
            checkAndSetVolume(stream, streamDesc.mIndexCur, output, outputDesc->device(), delayMs);
        }
    }
}
返回到函數 AudioPolicyManagerBase::setStrategyMute
—————————AudioPolicyManagerBase::setStreamMute————————————-
        }
    }
}
返回到函數 AudioPolicyManagerBase::setOutputDevice
————————–AudioPolicyManagerBase::setStrategyMute————————————–
        // wait for the PCM output buffers to empty before proceeding with the rest of the command
        usleep(outputDesc->mLatency*2*1000);
    }


    // do the routing
    AudioParameter param = AudioParameter();
    param.addInt(String8(AudioParameter::keyRouting), (int)device);
// 調用的其實是函數 AudioPolicyService::setParameters
// 會通過函數 AudioPolicyService::AudioCommandThread::parametersCommand 向 AudioCommandThread 的 command list
// 添加一個 command
// AudioPolicyService::AudioCommandThread::threadLoop 函數中會處理 command list 中的 command
// 對於 SET_PARAMETERS command ,最終調用瞭函數 AudioSystem::setParameters
// 調用瞭 AudioFlinger::setParameters 函數
// 調用瞭 AudioFlinger::ThreadBase::setParameters 函數添加成員到 mNewParameters
// 函數 AudioFlinger::MixerThread::checkForNewParameters_l 中會處理 mNewParameters 中的參數
// 函數 AudioFlinger::MixerThread::threadLoop 會調用函數 AudioFlinger::MixerThread::checkForNewParameters_l
    mpClientInterface->setParameters(mHardwareOutput, param.toString(), delayMs);
    // update stream volumes according to new device
    applyStreamVolumes(output, device, delayMs);
+++++++++++++++++++++++++AudioPolicyManagerBase::applyStreamVolumes+++++++++++++++++++++++++++++++++++++++
從函數 AudioPolicyManagerBase::setOutputDevice 進入:
void AudioPolicyManagerBase::applyStreamVolumes(audio_io_handle_t output, uint32_t device, int delayMs)
{
    LOGV("applyStreamVolumes() for output %d and device %x", output, device);


    for (int stream = 0; stream < AudioSystem::NUM_STREAM_TYPES; stream++) {
        checkAndSetVolume(stream, mStreams[stream].mIndexCur, output, device, delayMs);
++++++++++++++++++++++++++AudioPolicyManagerBase::checkAndSetVolume++++++++++++++++++++++++++++++++++++++
從函數 AudioPolicyManagerBase::applyStreamVolumes 進入:
status_t AudioPolicyManagerBase::checkAndSetVolume(int stream, int index, audio_io_handle_t output, uint32_t device, int delayMs, bool force /* = false */)
{


    // do not change actual stream volume if the stream is muted
// 如果 stream 是 mute ,並不真正去改變其音量
    if (mOutputs.valueFor(output)->mMuteCount[stream] != 0) {
        LOGV("checkAndSetVolume() stream %d muted count %d", stream, mOutputs.valueFor(output)->mMuteCount[stream]);
        return NO_ERROR;
    }


    // do not change in call volume if bluetooth is connected and vice versa
// 如果鏈接瞭藍牙耳機,則不去改變 VOICE_CALL 的音量,反之亦然
    if ((stream == AudioSystem::VOICE_CALL && mForceUse[AudioSystem::FOR_COMMUNICATION] == AudioSystem::FORCE_BT_SCO) ||
        (stream == AudioSystem::BLUETOOTH_SCO && mForceUse[AudioSystem::FOR_COMMUNICATION] != AudioSystem::FORCE_BT_SCO)) {
        LOGV("checkAndSetVolume() cannot set stream %d volume with force use = %d for comm",
             stream, mForceUse[AudioSystem::FOR_COMMUNICATION]);
        return INVALID_OPERATION;
    }


    float volume = computeVolume(stream, index, output, device);
+++++++++++++++++++++++++++AudioPolicyManagerBase::computeVolume+++++++++++++++++++++++++++++++++++++
從函數 AudioPolicyManagerBase::checkAndSetVolume 進入:
float AudioPolicyManagerBase::computeVolume(int stream, int index, audio_io_handle_t output, uint32_t device)
{
    float volume = 1.0;
    AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output);
    StreamDescriptor &streamDesc = mStreams[stream];


    if (device == 0) {
        device = outputDesc->device();
    }


    int volInt = (100 * (index – streamDesc.mIndexMin)) / (streamDesc.mIndexMax – streamDesc.mIndexMin);
    volume = AudioSystem::linearToLog(volInt);
++++++++++++++++++++++++++AudioSystem::linearToLog++++++++++++++++++++++++++++++++++++++
從函數 AudioPolicyManagerBase::computeVolume 進入:
// convert volume steps to natural log scale


// change this value to change volume scaling
static const float dBPerStep = 0.5f;
// shouldn't need to touch these
static const float dBConvert = -dBPerStep * 2.302585093f / 20.0f;
static const float dBConvertInverse = 1.0f / dBConvert;


float AudioSystem::linearToLog(int volume)
{
    // float v = volume ? exp(float(100 – volume) * dBConvert) : 0;
    // LOGD("linearToLog(%d)=%f", volume, v);
    // return v;
    return volume ? exp(float(100 – volume) * dBConvert) : 0;
}
返回到函數 AudioPolicyManagerBase::computeVolume
————————–AudioSystem::linearToLog————————————–


    // if a headset is connected, apply the following rules to ring tones and notifications
    // to avoid sound level bursts in user's ears:
    // – always attenuate ring tones and notifications volume by 6dB
    // – if music is playing, always limit the volume to current music volume,
    // with a minimum threshold at -36dB so that notification is always perceived.
// 如果連接瞭耳機,為瞭防止在用戶耳朵中產生爆音,對鈴聲和警告聲需要使用以下規則:
// – 對鈴聲和警告聲總是減弱 6dB。
// – 如果正在播放音樂,鈴聲和警告聲不應該高於音樂聲音,
// 不過,下限是 -36dB
    if ((device &
        (AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP |
        AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
        AudioSystem::DEVICE_OUT_WIRED_HEADSET |
        AudioSystem::DEVICE_OUT_WIRED_HEADPHONE)) &&
        ((getStrategy((AudioSystem::stream_type)stream) == STRATEGY_SONIFICATION) ||
         (stream == AudioSystem::SYSTEM)) &&
        streamDesc.mCanBeMuted) {
// Attenuation applied to STRATEGY_SONIFICATION streams when a headset is connected: 6dB
// #define SONIFICATION_HEADSET_VOLUME_FACTOR 0.5
        volume *= SONIFICATION_HEADSET_VOLUME_FACTOR;
        // when the phone is ringing we must consider that music could have been paused just before
        // by the music application and behave as if music was active if the last music track was
        // just stopped
        if (outputDesc->mRefCount[AudioSystem::MUSIC] || mLimitRingtoneVolume) {
            float musicVol = computeVolume(AudioSystem::MUSIC, mStreams[AudioSystem::MUSIC].mIndexCur, output, device);
// Min volume for STRATEGY_SONIFICATION streams when limited by music volume: -36dB
// #define SONIFICATION_HEADSET_VOLUME_MIN  0.016
            float minVol = (musicVol > SONIFICATION_HEADSET_VOLUME_MIN) ? musicVol : SONIFICATION_HEADSET_VOLUME_MIN;
            if (volume > minVol) {
                volume = minVol;
                LOGV("computeVolume limiting volume to %f musicVol %f", minVol, musicVol);
            }
        }
    }


    return volume;
}
返回到函數 AudioPolicyManagerBase::checkAndSetVolume
—————————AudioPolicyManagerBase::computeVolume————————————-
    // We actually change the volume if:
    // – the float value returned by computeVolume() changed
    // – the force flag is set
// 隻有當 compute 返回的音量與當前的音量不同,或者強制要求改音量時,才會去真正改變音量
    if (volume != mOutputs.valueFor(output)->mCurVolume[stream] ||
            force) {
        mOutputs.valueFor(output)->mCurVolume[stream] = volume;
        LOGV("setStreamVolume() for output %d stream %d, volume %f, delay %d", output, stream, volume, delayMs);
        if (stream == AudioSystem::VOICE_CALL ||
            stream == AudioSystem::DTMF ||
            stream == AudioSystem::BLUETOOTH_SCO) {
            // offset value to reflect actual hardware volume that never reaches 0
            // 1% corresponds roughly to first step in VOICE_CALL stream volume setting (see AudioService.java)
            volume = 0.01 + 0.99 * volume;
        }
        mpClientInterface->setStreamVolume((AudioSystem::stream_type)stream, volume, output, delayMs);
+++++++++++++++++++++++++++AudioPolicyService::setStreamVolume+++++++++++++++++++++++++++++++++++++
從函數 AudioPolicyManagerBase::checkAndSetVolume 進入:


status_t AudioPolicyService::setStreamVolume(AudioSystem::stream_type stream,
                                             float volume,
                                             audio_io_handle_t output,
                                             int delayMs)
{
// 函數 AudioPolicyService::AudioCommandThread::volumeCommand 會調用函數 AudioPolicyService::AudioCommandThread::insertCommand_l
// 往 mAudioCommands 中添加成員。
// 函數 AudioPolicyService::AudioCommandThread::threadLoop 會處理 mAudioCommands 中的成員
// 對於 SET_VOLUME 命令,調用瞭函數 AudioSystem::setStreamVolume
    return mAudioCommandThread->volumeCommand((int)stream, volume, (int)output, delayMs);
+++++++++++++++++++++++++++++AudioSystem::setStreamVolume+++++++++++++++++++++++++++++++++++
從函數 AudioPolicyService::setStreamVolume 進入:


status_t AudioSystem::setStreamVolume(int stream, float value, int output)
{
    if (uint32_t(stream) >= NUM_STREAM_TYPES) return BAD_VALUE;
    const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
    if (af == 0) return PERMISSION_DENIED;
    af->setStreamVolume(stream, value, output);
++++++++++++++++++++++++++++AudioFlinger::setStreamVolume++++++++++++++++++++++++++++++++++++
從函數 AudioSystem::setStreamVolume 進入:


status_t AudioFlinger::setStreamVolume(int stream, float value, int output)
{
    // check calling permissions
    if (!settingsAllowed()) {
        return PERMISSION_DENIED;
    }


    if (stream < 0 || uint32_t(stream) >= AudioSystem::NUM_STREAM_TYPES) {
        return BAD_VALUE;
    }


    AutoMutex lock(mLock);
    PlaybackThread *thread = NULL;
    if (output) {
        thread = checkPlaybackThread_l(output);
        if (thread == NULL) {
            return BAD_VALUE;
        }
    }


    mStreamTypes[stream].volume = value;


    if (thread == NULL) {
        for (uint32_t i = 0; i < mPlaybackThreads.size(); i++) {
           mPlaybackThreads.valueAt(i)->setStreamVolume(stream, value);
        }
    } else {
        thread->setStreamVolume(stream, value);
+++++++++++++++++++++++++++++AudioFlinger::PlaybackThread::setStreamVolume+++++++++++++++++++++++++++++++++++
從函數 AudioFlinger::setStreamVolume 進入:


status_t AudioFlinger::PlaybackThread::setStreamVolume(int stream, float value)
{
#ifdef LVMX
    int audioOutputType = LifeVibes::getMixerType(mId, mType);
    if (LifeVibes::audioOutputTypeIsLifeVibes(audioOutputType)) {
        LifeVibes::setStreamVolume(audioOutputType, stream, value);
    }
#endif
// 這一塊在看 testPlaybackHeadPositionIncrease 代碼的時候已經介紹過
    mStreamTypes[stream].volume = value;
    return NO_ERROR;
}
返回到函數 AudioFlinger::setStreamVolume
——————————AudioFlinger::PlaybackThread::setStreamVolume———————————-
    }


    return NO_ERROR;
}
返回到函數 AudioSystem::setStreamVolume
—————————-AudioFlinger::setStreamVolume————————————
    return NO_ERROR;
}
返回到函數 AudioPolicyService::setStreamVolume
—————————–AudioSystem::setStreamVolume———————————–
}
返回到函數 AudioPolicyManagerBase::checkAndSetVolume
—————————AudioPolicyService::setStreamVolume————————————-
    }


    if (stream == AudioSystem::VOICE_CALL ||
        stream == AudioSystem::BLUETOOTH_SCO) {
        float voiceVolume;
        // Force voice volume to max for bluetooth SCO as volume is managed by the headset
        if (stream == AudioSystem::VOICE_CALL) {
            voiceVolume = (float)index/(float)mStreams[stream].mIndexMax;
        } else {
            voiceVolume = 1.0;
        }
        if (voiceVolume != mLastVoiceVolume && output == mHardwareOutput) {
// 這兒與 setStreamVolume 函數類似,最終調用到瞭函數 AudioFlinger::setVoiceVolume
// 不過,setVoiceVolume最終會調用底層接口,改變硬件音量
// 這一塊也在看 testPlaybackHeadPositionIncrease 代碼的時候有看過
            mpClientInterface->setVoiceVolume(voiceVolume, delayMs);
            mLastVoiceVolume = voiceVolume;
        }
    }


    return NO_ERROR;
}
返回到函數 AudioPolicyManagerBase::applyStreamVolumes
————————–AudioPolicyManagerBase::checkAndSetVolume————————————–
    }
}
返回到函數 AudioPolicyManagerBase::setOutputDevice
————————-AudioPolicyManagerBase::applyStreamVolumes—————————————


    // if changing from a combined headset + speaker route, unmute media streams
// 前面,如果該條件成立,我們做瞭 mute 操作,此處要做恢復
    if (output == mHardwareOutput && AudioSystem::popCount(prevDevice) == 2) {
        setStrategyMute(STRATEGY_MEDIA, false, output, delayMs);
    }
}
返回到函數 AudioPolicyManagerBase::startOutput
—————————-AudioPolicyManagerBase::setOutputDevice————————————


    // handle special case for sonification while in call
    if (isInCall()) {
        handleIncallSonification(stream, true, false);
++++++++++++++++++++++++++++AudioPolicyManagerBase::handleIncallSonification++++++++++++++++++++++++++++++++++++
從函數 AudioPolicyManagerBase::startOutput 進入:


void AudioPolicyManagerBase::handleIncallSonification(int stream, bool starting, bool stateChange)
{
    // if the stream pertains to sonification strategy and we are in call we must
    // mute the stream if it is low visibility. If it is high visibility, we must play a tone
    // in the device used for phone strategy and play the tone if the selected device does not
    // interfere with the device used for phone strategy
    // if stateChange is true, we are called from setPhoneState() and we must mute or unmute as
    // many times as there are active tracks on the output
// 如果 stream 是 sonification strategy 的,並且其可見性低, 如果有電話打入則 mute 該 stream 。
// 如果其可見性高,我們必須在 phone strategy 使用的 device 中播放 tone ,並且如果選定的 device
// 與 phone strategy 不相幹的話,也要播放 tone 。
// 如果 stateChange 是 true ,則我們肯定是從函數 setPhoneState 進來的,
// 我們必須 mute / unmute output 中所有的 active track 。


    if (getStrategy((AudioSystem::stream_type)stream) == STRATEGY_SONIFICATION) {
        AudioOutputDescriptor *outputDesc = mOutputs.valueFor(mHardwareOutput);
        LOGV("handleIncallSonification() stream %d starting %d device %x stateChange %d",
                stream, starting, outputDesc->mDevice, stateChange);
        if (outputDesc->mRefCount[stream]) {
// 隻有 output 中存在 active 的該類型的 stream 時才做處理
            int muteCount = 1;
            if (stateChange) {
                muteCount = outputDesc->mRefCount[stream];
            }
            if (AudioSystem::isLowVisibility((AudioSystem::stream_type)stream)) {
++++++++++++++++++++++++++++AudioSystem::isLowVisibility++++++++++++++++++++++++++++++++++++
從函數 AudioPolicyManagerBase::handleIncallSonification 進入:


bool AudioSystem::isLowVisibility(stream_type stream)
{
// 以下這幾種 stream 的可見性低,其他的都是高的
    if (stream == AudioSystem::SYSTEM ||
        stream == AudioSystem::NOTIFICATION ||
        stream == AudioSystem::RING) {
        return true;
    } else {
        return false;
    }
}
返回到函數 AudioPolicyManagerBase::handleIncallSonification
—————————-AudioSystem::isLowVisibility————————————
                LOGV("handleIncallSonification() low visibility, muteCount %d", muteCount);
                for (int i = 0; i < muteCount; i++) {
                    setStreamMute(stream, starting, mHardwareOutput);
                }
            } else {
                LOGV("handleIncallSonification() high visibility");
                if (outputDesc->device() & getDeviceForStrategy(STRATEGY_PHONE)) {
                    LOGV("handleIncallSonification() high visibility muted, muteCount %d", muteCount);
                    for (int i = 0; i < muteCount; i++) {
                        setStreamMute(stream, starting, mHardwareOutput);
                    }
                }
                if (starting) {
                    mpClientInterface->startTone(ToneGenerator::TONE_SUP_CALL_WAITING, AudioSystem::VOICE_CALL);
                } else {
                    mpClientInterface->stopTone();
                }
            }
        }
    }
}
返回到函數 AudioPolicyManagerBase::startOutput
—————————-AudioPolicyManagerBase::handleIncallSonification————————————
    }


    // apply volume rules for current stream and device if necessary
    checkAndSetVolume(stream, mStreams[stream].mIndexCur, output, outputDesc->device());


    return NO_ERROR;
}
返回到函數 AudioPolicyService::startOutput
—————————–AudioPolicyManagerBase::startOutput———————————–
}
返回到函數 AudioSystem::startOutput
—————————–AudioPolicyService::startOutput———————————–
}
返回到函數 AudioFlinger::PlaybackThread::Track::start
—————————-AudioSystem::startOutput————————————
            thread->mLock.lock();
        }
        if (status == NO_ERROR) {
            PlaybackThread *playbackThread = (PlaybackThread *)thread.get();
            playbackThread->addTrack_l(this);
        } else {
            mState = state;
        }
    } else {
        status = BAD_VALUE;
    }
    return status;
}
###########################################################


&&&&&&&&&&&&&&&&&&&&&&&總結&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
各種聲音控制策略的實現主要在 Audio Policy Manager 中。
其中會根據 stream type 和當前的狀態對各種 stream 的音量作必要的修改。
以達成以下的優先級效果:


Priority  Strategy Type                           Stream Type
4            STRATEGY_PHONE               VOICE_CALL
                                                                   BLUETOOTH_SCO
3           STRATEGY_SONIFICATION    RING
                                                                   NOTIFICATION
                                                                   ALARM
                                                                   ENFORCED_AUDIBLE
2          STRATEGY_MEDIA                   SYSTEM
                                                                  TTS
                                                                   MUSIC
1         STRATEGY_DTMF                      DTMF


&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&

摘自:江風專欄

發佈留言