Android Audio代码分析 - Audio Strategy

2023-05-16


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

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

}
// 主要的处理是从这儿开始的 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);

需要知道每种策略分别是用来做什么的。
所以首先要知道策略对应的 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;
    }
}  

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


    setOutputDevice(output, getNewDevice(output));


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

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

  

    LOGV("getNewDevice() selected device %x", device);
    return device;  

}  

// 检查 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;
}

bool AudioPolicyManagerBase::isInCall() { // 函数 AudioPolicyManagerBase::setPhoneState 中会改变 mPhoneState 的值 // 调用关系:android_media_AudioSystem_setPhoneState // 调用 AudioSystem::setPhoneState // 调用 AudioPolicyService::setPhoneState // 调用 AudioPolicyManagerBase::setPhoneState return isStateInCall(mPhoneState); }
bool AudioPolicyManagerBase::isStateInCall(int state) { return ((state == AudioSystem::MODE_IN_CALL) || (state == AudioSystem::MODE_IN_COMMUNICATION)); 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 }; 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; }

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

        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


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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android Audio代码分析 - Audio Strategy 的相关文章

  • ACTION_VIEW 的 Intent.createChooser 仅显示默认浏览器

    我正在尝试使用 Intent createChooser 显示应用程序选择器对话框 该对话框将列出用户手机中所有可用的网络浏览器 我正在使用下面的代码 Intent browserIntent new Intent Intent ACTIO
  • android - EditText 打字速度很慢

    我的 EditText 在打字时响应速度很慢 这种滞后现象足以让我找到解决方案 我做了一些研究 发现了一个 SO 线程输入文本时 EditText 滞后 https stackoverflow com questions 6173591 a
  • 未找到 Gradle DSL 方法:“versionCode()”

    构建我的 Android 项目时遇到问题 我使用Grgit https github com ajoberstar grgit填写versionCode and versionName在 gradle 中 一切工作正常 直到我将 Andro
  • 合并两个位图图像(并排)

    任何人都可以帮助将两个位图图像合并为单个位图 在android中 并排 谢谢 尤瓦拉吉 您可以使用Canvas 查看这篇文章 http www jondev net articles Combining 2 Images in Androi
  • ImageView 中的全尺寸图像

    我正在尝试在 ImageView 中绘制图像 但我希望它不缩放 并根据需要使用滚动条 我怎样才能做到这一点 现在我只有一个可绘制集作为 XML 中 ImageView 的 android src 这会自动缩放图像以适应屏幕宽度 我读到这可能
  • 检查双精度值的等于和不等于条件

    我在比较两者时遇到困难double values using and 我创建了 6 个双变量并尝试进行比较If健康 状况 double a b c d e f if a b c d e f My code here in case of t
  • 如何从另一个xml文件动态更新xml文件?

    我想从另一个 xml 文件更新 xml 文件 我使用了一个 xml 文件 如下所示 one xml
  • 无法解析符号 FlutterActivity

    我使用 VCS gt Checkout from Version Control 将 flutter 项目从 github 导入到 Android Studio 中 现在我面临的问题是 Cannot resolve symbol Flutt
  • 在 Android 2.2 上运行 HelloCordova 时找不到类“android.webkit.WebResourceResponse”

    我尝试按照本教程进行操作 http docs phonegap com en 2 7 0 guide getting started android index md html Getting 20 Started 20with 20 An
  • 无法将 Tesseract OCR 模块添加到 Android Studio

    我按照此处找到的分步指南进行操作 https www codeproject com Articles 840623 Android Character Recognition https www codeproject com Artic
  • Android 手机应用意图

    我想在手机上启动手机应用程序作为意图 我正在使用这个代码 startActivity getPackageManager getLaunchIntentForPackage com android phone 但该函数抛出一个空指针异常 因
  • Python Kivy - 在本机网络浏览器中打开 url 的应用程序

    我尝试制作一个简单的应用程序 在单击 Screen One 上的按钮后 在 Kivy 中打开一个网页 我使用了这个主题 Python 在应用程序中直接显示网络浏览器 iframe https stackoverflow com questi
  • 在 Android 中使用 iText 读取或打开 PDF 文件

    我是 Android 应用程序开发新手 使用 iText 我完成了 PDF 创建并在创建的文件上写入 现在我想阅读该 PDF 文件 如何使用 iText 打开或阅读 PDF 文件 例子将是可观的 那么提前 哪个是渲染 PDF 文件的最佳库
  • Facebook LoginActivity 未正确显示

    我有一个使用 Facebook 登录的应用程序 我有 FacebookSDK 并且使用 com facebook LoginActivity 问题是 在 10 英寸平板电脑上 当显示软键盘时 活动无法正确显示 我使用的是 Samsung G
  • Android:单一活动,多个视图

    我不是 Android 专业人士 尽管我开发了一个包含 50 多个活动的应用程序 这使得该应用程序非常庞大 经过8周的开发 现在出现了一些问题 导致应用程序难以维护和升级 我正在处理的主要问题是 我无法将对象引用传递给活动的构造函数 事实上
  • 如何更改锁屏自定义文本(所有者信息)?

    我写了程序代码 String message This is test Settings System putString context getContentResolver Settings Secure LOCK PATTERN EN
  • 按名称查找视图

    是否可以通过名称而不是 id 来查找视图 findViewById R id someView 但我想做这样的事情 findViewByName someView 在处理 xml 时 您必须通过标识符查找视图 但是您可以使用以下方式查找标识
  • Android:如何通过右侧的十字按钮清除EditText

    我创建了一个EditText用于搜索 左侧包含搜索图标 右侧包含图标
  • Android:获取最新意图

    如何获取发送到活动的最后一个意图 的文档onNewIntent 建议我需要做这样的事情 class MyActivity public void onNewIntent Intent intent setIntent intent reac
  • 修改 ADW Android 启动器?

    我想更改和修改开源 ADW 启动器 启动器可在此处获取 https github com AnderWeb android packages apps Launcher https github com AnderWeb android p

随机推荐

  • 国标PS流解包(解封装)代码

    该代码最初的版本来自于互联网 xff0c 首先感谢前辈无私分享的精神 xff0c 这个PS流解析代码小巧和可读性好 xff0c 是学习PS格式的一个很好的参考例子 但原来的代码有不少Bug xff0c QuickGBLink在原先代码基础上
  • 错误./hello: error while loading shared libraries: libQtGui.so.4: cannot open shared object file:

    之前一直想在ARM 上跑qt xff0c 但都出现错误 xff1a hello error while loading shared libraries libQtGui so 4 cannot open shared object fil
  • linux eth0设置

    命令行设定IP地址 ifconfig eth0 192 168 1 12 将eth0IP设置为192 168 1 12 ifconfig eth0 up 使eth0使能 如果开发板与路由器连接 xff0c 并且路由器能够自动分配IP地址 x
  • printk打印不能显示到终端的解决方法

    printk与printf有个不同的地方 xff0c 就是printk有打印级别 使用printk时 xff0c Linux内核根据日志级别 xff0c 可能把消息打印到当前控制台上 xff0c 这个控制台是一个字符设备 这些消息从终端输出
  • qt socket通信中接收client发送是十六进制数据包

    在QT的服务端接收客户端发送的十六进制收据包 xff0c 经转换后显示在LineEdit上 xff0c 并把接收到的数据包转化为char 类型 xff0c 为后期数据处理做准备 recbuf在头文件类中一定义 xff1a QByteArra
  • 两个双口ram之间数据的传递

    1 如果两个双口ram数据位宽相同 xff0c 则采用时钟快的ram等待时钟慢的ram来完成从一个ram中读取数据并存储到另一个ram中 xff1b 例如从ram A中读取数据到ram xff22 中 xff0c xff52 xff41 x
  • + - 与>> <<运算优先级

    43 运算符的优先级高于 lt lt gt gt 位移运算符 span class hljs keyword int span mian span class hljs keyword int span a 61 span class hl
  • linux col 过滤控制字符

    参考http blog 51cto com jim123 1833502 使用过Unix系统的人肯定会知道man帮助的功能强大 xff0c 是官方的帮助文档 xff0c 我们平时可以通过它来查询不知道如何使用的命令或者查询linux的系统C
  • gcc 参数

    gcc gcc与 g 43 43 分别是GNU的C与 C 43 43 的编译器 xff0c 在编译工作中分4步 xff1a 1 预处理 xff0c 生成 i文件 2 编译器 xff0c 编译后停下来 xff0c 生成 o的目标文件 3 汇编
  • gdb 调试

    原文http linuxtools rst readthedocs io zh CN latest tool gdb html span class hljs variable span span class hljs number 1 s
  • Linux-C语言 网络TCP单次通信、多次通信、多线程通信逐步实现

    一 TCP通信 xff0c 只发送一次就结束程序 功能描述 xff1a 1 服务端一次只能连接一个客户端 2 客户端只能向服务端发送一次消息 xff0c 消息返回后客户端和服务器程序结束 3 客户端向服务端发送一个字符串 xff0c 服务端
  • 奇偶校验通俗易懂

    简介 xff1a 奇偶校验是奇校验和偶校验的统称 xff0c 就是在最低位或最高位添加一个校验位 xff0c 应用于主存储器信息的校验及字节传输的出错校验 原理 xff1a 奇校验 连同校验位使得所有位上的1相加为奇数 偶校验 xff1a
  • Ubuntu系统rosdep update报错的解决办法(2022.10.3亲测有效)

    目录 一 问题 xff1a Ubuntu22 04系统下面 xff0c rosdep update总是报错 二 方法一一道来 1 直接访问raw githubusercontent com是不行的 按照网上的解决办法先把ip地址找到 xff
  • Socket通信实验总结

    在实验设计的过程中遇到了不少困难 xff0c 先是服务器监听时怎么保持已有的socket 连接 xff0c 又能接受新的连接 在此用了 C 的 Dictionary lt string Socket gt socketDic 61 new
  • [Excel]Excel函数和用法(4)——查找字符串,SEARCH和FIND函数

    区别 xff1a SEARCH大小写不敏感 xff0c FIND大小写敏感 作用 xff1a 都是从左到右返回搜索到的字符串的起始位置 SEARCH语法 xff1a SEARCH find text within text start nu
  • Error: L6200E: Symbol B_DisCnctRelayTime multiply defined (by cdma_gps_hc.o and main.o).

    现象 xff1a 最近调试MDK的程序 xff0c 老是报这样的错误 L6200E Symbol B DisCnctRelayTime multiply defined by cdma gps o and main o 记录下来 xff1a
  • STM32 ADC用到的 抗脉冲滤波算法

    先介绍一下算法的基本思想 xff1a 在一组采样值中 xff0c 去掉 abandonMaxNum 个最大数据 xff0c 去掉 abandonMinNum 个最小数据 xff0c 余下的数据求平均值 函数功能 xff1a 抗脉冲滤波法 输
  • STM32使用内部振荡器及其和外部晶体振荡器的区别

    转自 xff1a http blog csdn net meic51 article details 8778518 在STM32上如果不使用外部晶振 xff0c OSC IN和OSC OUT的接法 如果使用内部RC振荡器而不使用外部晶振
  • Android的Audio系统

    转自 xff1a http blog csdn net gowyz article details 6019314 Android的Audio 系统 第一部分 Audio 系统综述 第二部分 Audio 系统和上层接口 第三部分 Audio
  • Android Audio代码分析 - Audio Strategy

    frameworks base services AudioFlinger cpp status t AudioFlinger PlaybackThread Track start status t status 61 NO ERROR L