美文网首页Android平台Audio系统
Android平台音量调节(二)Native的流程处理

Android平台音量调节(二)Native的流程处理

作者: 夕月风 | 来源:发表于2018-06-26 14:59 被阅读0次

    Native的流程处理

    前面只是说了AudioService中的逻辑,最终是通过AudioSystem.setStreamVolumeIndex(mStreamType, index, device);设置到native层的。那么我们就来看看native是怎么处理的。

    音频device

    setStreamVolumeIndex根据device和流类型来设置,换言之,每种设备的每种流类型的音量是分开的,可以不一样。比如蓝牙耳机的Music音量可以是15,而Speaker的音量可以是5。那么问题来了,上层根本没有 这些逻辑?这个是怎么实现的。我们先来看,怎么获取到的设备!

    * frameworks/base/services/core/java/com/android/server/audio/AudioService.java::VolumeStreamState
    
            public int observeDevicesForStream_syncVSS(boolean checkOthers) {
                final int devices = AudioSystem.getDevicesForStream(mStreamType);
                if (devices == mObservedDevices) {
                    return devices;
                }
                final int prevDevices = mObservedDevices;
                mObservedDevices = devices;
                if (checkOthers) {
                    // one stream's devices have changed, check the others
                    observeDevicesForStreams(mStreamType);
                }
                // log base stream changes to the event log
                if (mStreamVolumeAlias[mStreamType] == mStreamType) {
                    EventLogTags.writeStreamDevicesChanged(mStreamType, prevDevices, devices);
                }
                sendBroadcastToAll(mStreamDevicesChanged
                        .putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_DEVICES, prevDevices)
                        .putExtra(AudioManager.EXTRA_VOLUME_STREAM_DEVICES, devices));
                return devices;
            }
    

    device是通过AudioSystem.getDevicesForStream(mStreamType)获取到的,mStreamType是流类型,不是映射的别名。

    native的getDevicesForStream函数如下:

    audio_devices_t AudioSystem::getDevicesForStream(audio_stream_type_t stream)
    {
        const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
        if (aps == 0) return AUDIO_DEVICE_NONE;
        return aps->getDevicesForStream(stream);
    }
    

    最后都是通过AudioPolicy来决定的。

    * frameworks/av/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
    
    audio_devices_t AudioPolicyService::getDevicesForStream(audio_stream_type_t stream)
    {
        if (uint32_t(stream) >= AUDIO_STREAM_PUBLIC_CNT) {
            return AUDIO_DEVICE_NONE;
        }
        if (mAudioPolicyManager == NULL) {
            return AUDIO_DEVICE_NONE;
        }
        Mutex::Autolock _l(mLock);
        return mAudioPolicyManager->getDevicesForStream(stream);
    }
    

    mAudioPolicyManagers是AudioPolicy的核心,AudioPolicyService起来的时候就创建了mAudioPolicyManager以及相应的一些线程。

    frameworks/av/services/audiopolicy/service/AudioPolicyService.cpp
    
    void AudioPolicyService::onFirstRef()
    {
        {
            Mutex::Autolock _l(mLock);
    
            // start tone playback thread
            mTonePlaybackThread = new AudioCommandThread(String8("ApmTone"), this);
            // start audio commands thread
            mAudioCommandThread = new AudioCommandThread(String8("ApmAudio"), this);
            // start output activity command thread
            mOutputCommandThread = new AudioCommandThread(String8("ApmOutput"), this);
    
            mAudioPolicyClient = new AudioPolicyClient(this);
            mAudioPolicyManager = createAudioPolicyManager(mAudioPolicyClient);
        }
        // load audio processing modules
        sp<AudioPolicyEffects>audioPolicyEffects = new AudioPolicyEffects();
        {
            Mutex::Autolock _l(mLock);
            mAudioPolicyEffects = audioPolicyEffects;
        }
    }
    

    mAudioPolicyManager通过createAudioPolicyManager函数创建的,AOSP的createAudioPolicyManager如下:

    * frameworks/av/services/audiopolicy/manager/AudioPolicyFactory.cpp
    
    extern "C" AudioPolicyInterface* createAudioPolicyManager(
            AudioPolicyClientInterface *clientInterface)
    {
        return new AudioPolicyManager(clientInterface);
    }
    

    Vendor也可以自己实现自己的AudioPolicyManager,比如高通的:

    * hardware/qcom/audio/policy_hal/AudioPolicyManager.cpp
    
    extern "C" AudioPolicyInterface* createAudioPolicyManager(
             AudioPolicyClientInterface *clientInterface)
    {
         return new AudioPolicyManagerCustom(clientInterface);
    }
    

    我们继续来看getDevicesForStream函数:

    * frameworks/av/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
    
    audio_devices_t AudioPolicyManager::getDevicesForStream(audio_stream_type_t stream) {
        // By checking the range of stream before calling getStrategy, we avoid
        // getStrategy's behavior for invalid streams.  getStrategy would do a ALOGE
        // and then return STRATEGY_MEDIA, but we want to return the empty set.
        if (stream < (audio_stream_type_t) 0 || stream >= AUDIO_STREAM_PUBLIC_CNT) {
            return AUDIO_DEVICE_NONE;
        }
        audio_devices_t devices = AUDIO_DEVICE_NONE;
        for (int curStream = 0; curStream < AUDIO_STREAM_FOR_POLICY_CNT; curStream++) {
            if (!streamsMatchForvolume(stream, (audio_stream_type_t)curStream)) {
                continue;
            }
            routing_strategy curStrategy = getStrategy((audio_stream_type_t)curStream);
            audio_devices_t curDevices =
                    getDeviceForStrategy((routing_strategy)curStrategy, false /*fromCache*/);
            SortedVector<audio_io_handle_t> outputs = getOutputsForDevice(curDevices, mOutputs);
            for (size_t i = 0; i < outputs.size(); i++) {
                sp<AudioOutputDescriptor> outputDesc = mOutputs.valueFor(outputs[i]);
                if (outputDesc->isStreamActive((audio_stream_type_t)curStream)) {
                    curDevices |= outputDesc->device();
                }
            }
            devices |= curDevices;
        }
    
        /*Filter SPEAKER_SAFE out of results, as AudioService doesn't know about it
          and doesn't really need to.*/
        if (devices & AUDIO_DEVICE_OUT_SPEAKER_SAFE) {
            devices |= AUDIO_DEVICE_OUT_SPEAKER;
            devices &= ~AUDIO_DEVICE_OUT_SPEAKER_SAFE;
        }
        return devices;
    }
    
    • streamsMatchForvolume 就是判断两个是否相等
    • getStrategy函数,将stream转换为Strategy
    • getDeviceForStrategy 根据 Strategy 获取device
    • getOutputsForDevice 获取device相关的output
    • output相关的device,outputDesc->device()

    音频流到音频策略的映射

    在native会将流转换为策略,根据策略选择设备等。

    * frameworks/av/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
    
    routing_strategy AudioPolicyManager::getStrategy(audio_stream_type_t stream) const
    {
        ALOG_ASSERT(stream != AUDIO_STREAM_PATCH,"getStrategy() called for AUDIO_STREAM_PATCH");
        return mEngine->getStrategyForStream(stream);
    }
    

    mEngine是在AudioPolicyManager的构造函数中生成的。

    AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterface)
        :
    ... ...
    {
        ... ...
    
        // Once policy config has been parsed, retrieve an instance of the engine and initialize it.
        audio_policy::EngineInstance *engineInstance = audio_policy::EngineInstance::getInstance();
        if (!engineInstance) {
            ALOGE("%s:  Could not get an instance of policy engine", __FUNCTION__);
            return;
        }
        // Retrieve the Policy Manager Interface
        mEngine = engineInstance->queryInterface<AudioPolicyManagerInterface>();
        if (mEngine == NULL) {
            ALOGE("%s: Failed to get Policy Engine Interface", __FUNCTION__);
            return;
        }
        mEngine->setObserver(this);
        status_t status = mEngine->initCheck();
    

    Engine可以可以配置的,根据 USE_CONFIGURABLE_AUDIO_POLICY定义,我们这里分析Default的enginedefault。

    * frameworks/av/services/audiopolicy/enginedefault/src/Engine.cpp
    
    routing_strategy Engine::getStrategyForStream(audio_stream_type_t stream)
    {
        // stream to strategy mapping
        switch (stream) {
        case AUDIO_STREAM_VOICE_CALL:
        case AUDIO_STREAM_BLUETOOTH_SCO:
            return STRATEGY_PHONE;
        case AUDIO_STREAM_RING:
        case AUDIO_STREAM_ALARM:
            return STRATEGY_SONIFICATION;
        case AUDIO_STREAM_NOTIFICATION:
            return STRATEGY_SONIFICATION_RESPECTFUL;
        case AUDIO_STREAM_DTMF:
            return STRATEGY_DTMF;
        default:
            ALOGE("unknown stream type %d", stream);
        case AUDIO_STREAM_SYSTEM:
            // NOTE: SYSTEM stream uses MEDIA strategy because muting music and switching outputs
            // while key clicks are played produces a poor result
        case AUDIO_STREAM_MUSIC:
            return STRATEGY_MEDIA;
        case AUDIO_STREAM_ENFORCED_AUDIBLE:
            return STRATEGY_ENFORCED_AUDIBLE;
        case AUDIO_STREAM_TTS:
            return STRATEGY_TRANSMITTED_THROUGH_SPEAKER;
        case AUDIO_STREAM_ACCESSIBILITY:
            return STRATEGY_ACCESSIBILITY;
        case AUDIO_STREAM_REROUTING:
            return STRATEGY_REROUTING;
        }
    }
    

    native声音流的定义:

    * system/media/audio/include/system/audio-base.h
    
    typedef enum {
        AUDIO_STREAM_DEFAULT = -1, // (-1)
        AUDIO_STREAM_MIN = 0,
        AUDIO_STREAM_VOICE_CALL = 0,
        AUDIO_STREAM_SYSTEM = 1,
        AUDIO_STREAM_RING = 2,
        AUDIO_STREAM_MUSIC = 3,
        AUDIO_STREAM_ALARM = 4,
        AUDIO_STREAM_NOTIFICATION = 5,
        AUDIO_STREAM_BLUETOOTH_SCO = 6,
        AUDIO_STREAM_ENFORCED_AUDIBLE = 7,
        AUDIO_STREAM_DTMF = 8,
        AUDIO_STREAM_TTS = 9,
        AUDIO_STREAM_ACCESSIBILITY = 10,
        AUDIO_STREAM_REROUTING = 11,
        AUDIO_STREAM_PATCH = 12,
        AUDIO_STREAM_PUBLIC_CNT = 11, // (ACCESSIBILITY + 1)
        AUDIO_STREAM_FOR_POLICY_CNT = 12, // PATCH
        AUDIO_STREAM_CNT = 13, // (PATCH + 1)
    } audio_stream_type_t;
    

    策略定义:

    * frameworks/av/services/audiopolicy/common/include/RoutingStrategy.h
    
    enum routing_strategy {
        STRATEGY_MEDIA,
        STRATEGY_PHONE,
        STRATEGY_SONIFICATION,
        STRATEGY_SONIFICATION_RESPECTFUL,
        STRATEGY_DTMF,
        STRATEGY_ENFORCED_AUDIBLE,
        STRATEGY_TRANSMITTED_THROUGH_SPEAKER,
        STRATEGY_ACCESSIBILITY,
        STRATEGY_REROUTING,
        NUM_STRATEGIES
    };
    

    相互将的对应关系如下:

    流代号 流类型 Strategy映射 描述
    0 STREAM_VOICE_CALL STRATEGY_PHONE 通话相关音频
    6 AUDIO_STREAM_BLUETOOTH_SCO STRATEGY_PHONE 蓝牙SCO通话相关音频
    2 AUDIO_STREAM_RING STRATEGY_SONIFICATION 铃声
    4 AUDIO_STREAM_ALARM STRATEGY_SONIFICATION 闹钟
    5 AUDIO_STREAM_NOTIFICATION STRATEGY_SONIFICATION_RESPECTFUL 通知音
    8 AUDIO_STREAM_DTMF STRATEGY_DTMF DTMF音
    1 AUDIO_STREAM_SYSTEM STRATEGY_MEDIA 系统音
    3 AUDIO_STREAM_MUSIC STRATEGY_MEDIA 媒体音
    7 AUDIO_STREAM_ENFORCED_AUDIBLE STRATEGY_ENFORCED_AUDIBLE 强制为Speaker出声
    9 AUDIO_STREAM_TTS STRATEGY_TRANSMITTED_THROUGH_SPEAKER TTS 播报
    10 AUDIO_STREAM_ACCESSIBILITY STRATEGY_ACCESSIBILITY 辅助音
    11 AUDIO_STREAM_REROUTING STRATEGY_REROUTING 动态输出混音

    AUDIO_STREAM_ENFORCED_AUDIBLE 这个流是不让用户静音的,强制为Speaker出声。比如拍照音,拍照音是必须Speaker出声的,防偷拍。

    回到getDevicesForStream函数~

    获取设备

    根据流类型,获取到策略后,再根据策略获取相关的设备。

    * frameworks/av/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
    
    audio_devices_t AudioPolicyManager::getDeviceForStrategy(routing_strategy strategy,
                                                             bool fromCache)
    {
        // Routing
        // see if we have an explicit route
        // scan the whole RouteMap, for each entry, convert the stream type to a strategy
        // (getStrategy(stream)).
        // if the strategy from the stream type in the RouteMap is the same as the argument above,
        // and activity count is non-zero and the device in the route descriptor is available
        // then select this device.
        for (size_t routeIndex = 0; routeIndex < mOutputRoutes.size(); routeIndex++) {
            sp<SessionRoute> route = mOutputRoutes.valueAt(routeIndex);
            routing_strategy routeStrategy = getStrategy(route->mStreamType);
            if ((routeStrategy == strategy) && route->isActiveOrChanged() &&
                    (mAvailableOutputDevices.indexOf(route->mDeviceDescriptor) >= 0)) {
                return route->mDeviceDescriptor->type();
            }
        }
    
        if (fromCache) {
            ALOGVV("getDeviceForStrategy() from cache strategy %d, device %x",
                  strategy, mDeviceForStrategy[strategy]);
            return mDeviceForStrategy[strategy];
        }
        return mEngine->getDeviceForStrategy(strategy);
    }
    

    最终通过mEngine来实现的。STRATEGY_TRANSMITTED_THROUGH_SPEAKER

    * frameworks/av/services/audiopolicy/enginedefault/src/Engine.cpp
    
    audio_devices_t Engine::getDeviceForStrategy(routing_strategy strategy) const
    {
        DeviceVector availableOutputDevices = mApmObserver->getAvailableOutputDevices();
        DeviceVector availableInputDevices = mApmObserver->getAvailableInputDevices();
    
        const SwAudioOutputCollection &outputs = mApmObserver->getOutputs();
    
        return getDeviceForStrategyInt(strategy, availableOutputDevices,
                                       availableInputDevices, outputs);
    }
    

    主要实现在 getDeviceForStrategyInt 函数中。getDeviceForStrategyInt函数非常长。这里就不贴全部的代码。起主要有以下几个方面决定:

    1. 是否在通话中
    2. 当前是什么流出于Active状态
    3. 有没有ForceUse

    我们来看看STRATEGY_SONIFICATION_RESPECTFUL,AUDIO_STREAM_NOTIFICATION场景的:

        case STRATEGY_SONIFICATION_RESPECTFUL:
            if (isInCall()) {
                device = getDeviceForStrategyInt(
                        STRATEGY_SONIFICATION, availableOutputDevices, availableInputDevices, outputs);
            } else if (outputs.isStreamActiveRemotely(AUDIO_STREAM_MUSIC,
                    SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY)) {
                // while media is playing on a remote device, use the the sonification behavior.
                // Note that we test this usecase before testing if media is playing because
                //   the isStreamActive() method only informs about the activity of a stream, not
                //   if it's for local playback. Note also that we use the same delay between both tests
                device = getDeviceForStrategyInt(
                        STRATEGY_SONIFICATION, availableOutputDevices, availableInputDevices, outputs);
                //user "safe" speaker if available instead of normal speaker to avoid triggering
                //other acoustic safety mechanisms for notification
                if ((device & AUDIO_DEVICE_OUT_SPEAKER) &&
                        (availableOutputDevicesType & AUDIO_DEVICE_OUT_SPEAKER_SAFE)) {
                    device |= AUDIO_DEVICE_OUT_SPEAKER_SAFE;
                    device &= ~AUDIO_DEVICE_OUT_SPEAKER;
                }
            } else if (outputs.isStreamActive(
                                    AUDIO_STREAM_MUSIC, SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY)
                        || outputs.isStreamActive(
                                AUDIO_STREAM_ACCESSIBILITY, SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY))
            {
                // while media/a11y is playing (or has recently played), use the same device
                device = getDeviceForStrategyInt(
                        STRATEGY_MEDIA, availableOutputDevices, availableInputDevices, outputs);
            } else {
                // when media is not playing anymore, fall back on the sonification behavior
                device = getDeviceForStrategyInt(
                        STRATEGY_SONIFICATION, availableOutputDevices, availableInputDevices, outputs);
                //user "safe" speaker if available instead of normal speaker to avoid triggering
                //other acoustic safety mechanisms for notification
                if ((device & AUDIO_DEVICE_OUT_SPEAKER) &&
                        (availableOutputDevicesType & AUDIO_DEVICE_OUT_SPEAKER_SAFE)) {
                    device |= AUDIO_DEVICE_OUT_SPEAKER_SAFE;
                    device &= ~AUDIO_DEVICE_OUT_SPEAKER;
                }
            }
            break;
    
    1. 如果是通话中,转换为STRATEGY_SONIFICATION
    2. 如果Remote Music Active,转换为STRATEGY_SONIFICATION,但是如果支持SPEAKER_SAFE,优先使用SPEAKER_SAFE
    3. 如果AUDIO_STREAM_MUSIC或AUDIO_STREAM_ACCESSIBILITY,转换为STRATEGY_MEDIA
    4. 其余情况,采用STRATEGY_SONIFICATION,但是如果支持SPEAKER_SAFE,优先使用SPEAKER_SAFE

    具体情况,具体看,比较复杂的。Anyway,到此,我们的device算是获取到了。

    Native设置音量

    音量都是通过AudioSystem的setStreamVolumeIndex函数,设置到native的:

            public void applyDeviceVolume_syncVSS(int device) {
                int index;
                if (mIsMuted) {
                    index = 0;
                } else if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 && mAvrcpAbsVolSupported) {
                    index = getAbsoluteVolumeIndex((getIndex(device) + 5)/10);
                } else if ((device & mFullVolumeDevices) != 0) {
                    index = (mIndexMax + 5)/10;
                } else {
                    index = (getIndex(device) + 5)/10;
                }
                AudioSystem.setStreamVolumeIndex(mStreamType, 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)
    {
    
        ... ...
    
        // Force max volume if stream cannot be muted
        if (!mVolumeCurves->canBeMuted(stream)) index = mVolumeCurves->getVolumeIndexMax(stream);
    
        ALOGV("setStreamVolumeIndex() stream %d, device %08x, index %d",
              stream, device, index);
    
        // update other private stream volumes which follow this one
        for (int curStream = 0; curStream < AUDIO_STREAM_FOR_POLICY_CNT; curStream++) {
            if (!streamsMatchForvolume(stream, (audio_stream_type_t)curStream)) {
                continue;
            }
            mVolumeCurves->addCurrentVolumeIndex((audio_stream_type_t)curStream, device, index);
        }
    
        status_t status = NO_ERROR;
        for (size_t i = 0; i < mOutputs.size(); i++) {
            sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
            audio_devices_t curDevice = Volume::getDeviceForVolume(desc->device());
            for (int curStream = 0; curStream < AUDIO_STREAM_FOR_POLICY_CNT; curStream++) {
                if (!streamsMatchForvolume(stream, (audio_stream_type_t)curStream)) {
                    continue;
                }
                if (!(desc->isStreamActive((audio_stream_type_t)curStream) ||
                        (isInCall() && (curStream == AUDIO_STREAM_VOICE_CALL)))) {
                    continue;
                }
                routing_strategy curStrategy = getStrategy((audio_stream_type_t)curStream);
                audio_devices_t curStreamDevice = Volume::getDeviceForVolume(getDeviceForStrategy(
                        curStrategy, false /*fromCache*/));
                if ((device != AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME) &&
                        ((curStreamDevice & device) == 0)) {
                    continue;
                }
                bool applyVolume;
                if (device != AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME) {
                    curStreamDevice |= device;
                    applyVolume = (curDevice & curStreamDevice) != 0;
                } else {
                    applyVolume = !mVolumeCurves->hasVolumeIndexForDevice(
                            stream, curStreamDevice);
                }
    
                if (applyVolume) {
                    //FIXME: workaround for truncated touch sounds
                    // delayed volume change for system stream to be removed when the problem is
                    // handled by system UI
                    status_t volStatus =
                            checkAndSetVolume((audio_stream_type_t)curStream, index, desc, curDevice,
                                (stream == AUDIO_STREAM_SYSTEM) ? TOUCH_SOUND_FIXED_DELAY_MS : 0);
                    if (volStatus != NO_ERROR) {
                        status = volStatus;
                    }
                }
            }
        }
        return status;
    }
    
    • mVolumeCurves, 流的描述,是一个集合,用StreamDescriptorCollection表示。具体的流用StreamDescriptor描述。前面的流都是用一个int类型来描述的,现在用StreamDescriptor来描述了。
    frameworks/av/services/audiopolicy/common/managerdefinitions/src/StreamDescriptor.cpp
    
    • Volume的index值,通过addCurrentVolumeIndex,保存到了StreamDescriptor中:
    * frameworks/av/services/audiopolicy/common/managerdefinitions/src/StreamDescriptor.cpp
    
    void StreamDescriptor::addCurrentVolumeIndex(audio_devices_t device, int index)
    {
        mIndexCur.add(device, index);
    }
    

    Volume按照device保存到mIndexCur中:

    KeyedVector<audio_devices_t, int> mIndexCur;
    
    • mOutputs 当前的输出设备
      每一个输出设备用SwAudioOutputDescriptor描述:
    frameworks/av/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
    
    • 获取设备,再次确认
    Volume::getDeviceForVolume
    
        static audio_devices_t getDeviceForVolume(audio_devices_t device)
        {
            if (device == AUDIO_DEVICE_NONE) {
                device =  AUDIO_DEVICE_OUT_SPEAKER;
            } else if (popcount(device) > 1) {
                if (device & AUDIO_DEVICE_OUT_SPEAKER) {
                    device = AUDIO_DEVICE_OUT_SPEAKER;
                } else if (device & AUDIO_DEVICE_OUT_SPEAKER_SAFE) {
                    device = AUDIO_DEVICE_OUT_SPEAKER_SAFE;
                } else if (device & AUDIO_DEVICE_OUT_HDMI_ARC) {
                    device = AUDIO_DEVICE_OUT_HDMI_ARC;
                } else if (device & AUDIO_DEVICE_OUT_AUX_LINE) {
                    device = AUDIO_DEVICE_OUT_AUX_LINE;
                } else if (device & AUDIO_DEVICE_OUT_SPDIF) {
                    device = AUDIO_DEVICE_OUT_SPDIF;
                } else {
                    device = (audio_devices_t)(device & AUDIO_DEVICE_OUT_ALL_A2DP);
                }
            }
    
            /*SPEAKER_SAFE is an alias of SPEAKER for purposes of volume control*/
            if (device == AUDIO_DEVICE_OUT_SPEAKER_SAFE)
                device = AUDIO_DEVICE_OUT_SPEAKER;
    
            return device;
        }
    
    • 根据流获取策略,根据测试获取device,再根据device判断是否需要应用音量,音量是通过checkAndSetVolume来生效的。

    如果当前没有任何流处在active,音量设置时是没有生效的,这根据前面的applyVolume来决定。如果这个时候没有生效,后续在startSource时,也会checkAndSetVolume。

    * frameworks/av/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
    
    status_t AudioPolicyManager::checkAndSetVolume(audio_stream_type_t stream,
                                                       int index,
                                                       const sp<AudioOutputDescriptor>& outputDesc,
                                                       audio_devices_t device,
                                                       int delayMs,
                                                       bool force)
    {
        // 静音,不修改音量值
        if (outputDesc->mMuteCount[stream] != 0) {
            ALOGVV("checkAndSetVolume() stream %d muted count %d",
                  stream, outputDesc->mMuteCount[stream]);
            return NO_ERROR;
        }
        audio_policy_forced_cfg_t forceUseForComm =
                mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_COMMUNICATION);
        // 如果是蓝牙通话,不修改音量值,反之亦然
        if ((stream == AUDIO_STREAM_VOICE_CALL && forceUseForComm == AUDIO_POLICY_FORCE_BT_SCO) ||
            (stream == AUDIO_STREAM_BLUETOOTH_SCO && forceUseForComm != AUDIO_POLICY_FORCE_BT_SCO)) {
            ALOGV("checkAndSetVolume() cannot set stream %d volume with force use = %d for comm",
                 stream, forceUseForComm);
            return INVALID_OPERATION;
        }
    
        if (device == AUDIO_DEVICE_NONE) {
            device = outputDesc->device();
        }
    
        // 关键代码computeVolume,计算音量值,将index值转换为Db值。
        float volumeDb = computeVolume(stream, index, device);
        if (outputDesc->isFixedVolume(device)) {
            volumeDb = 0.0f;
        }
    
        // 设置音量
        outputDesc->setVolume(volumeDb, stream, device, delayMs, force);
    
        // 通话音量,SCO设置为最大,headset自己管理。
        if (stream == AUDIO_STREAM_VOICE_CALL ||
            stream == AUDIO_STREAM_BLUETOOTH_SCO) {
            float voiceVolume;
            if (stream == AUDIO_STREAM_VOICE_CALL) {
                voiceVolume = (float)index/(float)mVolumeCurves->getVolumeIndexMax(stream);
            } else {
                voiceVolume = 1.0;
            }
    
            if (voiceVolume != mLastVoiceVolume) {
                mpClientInterface->setVoiceVolume(voiceVolume, delayMs);
                mLastVoiceVolume = voiceVolume;
            }
        }
    
        return NO_ERROR;
    }
    

    计算音量Db值

    * frameworks/av/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
    
    float AudioPolicyManager::computeVolume(audio_stream_type_t stream,
                                            int index,
                                            audio_devices_t device)
    {
        float volumeDB = mVolumeCurves->volIndexToDb(stream, Volume::getDeviceCategory(device), index);
    
        // 处理辅助功能开启,响铃的场景
        if ((stream == AUDIO_STREAM_ACCESSIBILITY)
                && (AUDIO_MODE_RINGTONE == mEngine->getPhoneState())
                && isStreamActive(AUDIO_STREAM_RING, 0)) {
            const float ringVolumeDB = computeVolume(AUDIO_STREAM_RING, index, device);
            return ringVolumeDB - 4 > volumeDB ? ringVolumeDB - 4 : volumeDB;
        }
    
        // 通话中的场景
        if ((stream != AUDIO_STREAM_VOICE_CALL) && (device & AUDIO_DEVICE_OUT_EARPIECE) && isInCall()) {
            switch (stream) {
            case AUDIO_STREAM_SYSTEM:
            case AUDIO_STREAM_RING:
            case AUDIO_STREAM_MUSIC:
            case AUDIO_STREAM_ALARM:
            case AUDIO_STREAM_NOTIFICATION:
            case AUDIO_STREAM_ENFORCED_AUDIBLE:
            case AUDIO_STREAM_DTMF:
            case AUDIO_STREAM_ACCESSIBILITY: {
                const float maxVoiceVolDb = computeVolume(AUDIO_STREAM_VOICE_CALL, index, device)
                        + IN_CALL_EARPIECE_HEADROOM_DB;
                if (volumeDB > maxVoiceVolDb) {
                    ALOGV("computeVolume() stream %d at vol=%f overriden by stream %d at vol=%f",
                            stream, volumeDB, AUDIO_STREAM_VOICE_CALL, maxVoiceVolDb);
                    volumeDB = maxVoiceVolDb;
                }
                } break;
            default:
                break;
            }
        }
    
        // 插耳机的场景,防止响铃等声音过大
        const routing_strategy stream_strategy = getStrategy(stream);
        if ((device & (AUDIO_DEVICE_OUT_BLUETOOTH_A2DP |
                AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
                AUDIO_DEVICE_OUT_WIRED_HEADSET |
                AUDIO_DEVICE_OUT_WIRED_HEADPHONE |
                AUDIO_DEVICE_OUT_USB_HEADSET)) &&
            ((stream_strategy == STRATEGY_SONIFICATION)
                    || (stream_strategy == STRATEGY_SONIFICATION_RESPECTFUL)
                    || (stream == AUDIO_STREAM_SYSTEM)
                    || ((stream_strategy == STRATEGY_ENFORCED_AUDIBLE) &&
                        (mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) == AUDIO_POLICY_FORCE_NONE))) &&
                mVolumeCurves->canBeMuted(stream)) {
            // 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 (isStreamActive(AUDIO_STREAM_MUSIC, SONIFICATION_HEADSET_MUSIC_DELAY) ||
                    mLimitRingtoneVolume) {
                volumeDB += SONIFICATION_HEADSET_VOLUME_FACTOR_DB;
                audio_devices_t musicDevice = getDeviceForStrategy(STRATEGY_MEDIA, true /*fromCache*/);
                float musicVolDB = computeVolume(AUDIO_STREAM_MUSIC,
                                                 mVolumeCurves->getVolumeIndex(AUDIO_STREAM_MUSIC,
                                                                                  musicDevice),
                                                 musicDevice);
                float minVolDB = (musicVolDB > SONIFICATION_HEADSET_VOLUME_MIN_DB) ?
                        musicVolDB : SONIFICATION_HEADSET_VOLUME_MIN_DB;
                if (volumeDB > minVolDB) {
                    volumeDB = minVolDB;
                    ALOGV("computeVolume limiting volume to %f musicVol %f", minVolDB, musicVolDB);
                }
                if (device & (AUDIO_DEVICE_OUT_BLUETOOTH_A2DP |
                        AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES)) {
                    // on A2DP, also ensure notification volume is not too low compared to media when
                    // intended to be played
                    if ((volumeDB > -96.0f) &&
                            (musicVolDB - SONIFICATION_A2DP_MAX_MEDIA_DIFF_DB > volumeDB)) {
                        ALOGV("computeVolume increasing volume for stream=%d device=0x%X from %f to %f",
                                stream, device,
                                volumeDB, musicVolDB - SONIFICATION_A2DP_MAX_MEDIA_DIFF_DB);
                        volumeDB = musicVolDB - SONIFICATION_A2DP_MAX_MEDIA_DIFF_DB;
                    }
                }
            } else if ((Volume::getDeviceForVolume(device) != AUDIO_DEVICE_OUT_SPEAKER) ||
                    stream_strategy != STRATEGY_SONIFICATION) {
                volumeDB += SONIFICATION_HEADSET_VOLUME_FACTOR_DB;
            }
        }
    
        return volumeDB;
    }
    

    Db值通过mVolumeCurves->volIndexToDb,进行转换,转换后,再根据实际的场景进行调整。

    我们先来看看Volume::getDeviceCategory,Audio这边就死麻烦,各种概念。device_category将设备进行分类。

    * frameworks/av/services/audiopolicy/common/include/Volume.h
    
        static device_category getDeviceCategory(audio_devices_t device)
        {
            switch(getDeviceForVolume(device)) {
            case AUDIO_DEVICE_OUT_EARPIECE:
                return DEVICE_CATEGORY_EARPIECE;
            case AUDIO_DEVICE_OUT_WIRED_HEADSET:
            case AUDIO_DEVICE_OUT_WIRED_HEADPHONE:
            case AUDIO_DEVICE_OUT_BLUETOOTH_SCO:
            case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET:
            case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP:
            case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES:
            case AUDIO_DEVICE_OUT_USB_HEADSET:
                return DEVICE_CATEGORY_HEADSET;
            case AUDIO_DEVICE_OUT_LINE:
            case AUDIO_DEVICE_OUT_AUX_DIGITAL:
            case AUDIO_DEVICE_OUT_USB_DEVICE:
                return DEVICE_CATEGORY_EXT_MEDIA;
            case AUDIO_DEVICE_OUT_SPEAKER:
            case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT:
            case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER:
            case AUDIO_DEVICE_OUT_USB_ACCESSORY:
            case AUDIO_DEVICE_OUT_REMOTE_SUBMIX:
            default:
                return DEVICE_CATEGORY_SPEAKER;
            }
        }
    

    volIndexToDb函数 如下:

    float StreamDescriptorCollection::volIndexToDb(audio_stream_type_t stream, device_category category,
                                                   int indexInUi) const
    {
        const StreamDescriptor &streamDesc = valueAt(stream);
        return Gains::volIndexToDb(streamDesc.getVolumeCurvePoint(category),
                                   streamDesc.getVolumeIndexMin(), streamDesc.getVolumeIndexMax(),
                                   indexInUi);
    }
    
    float Gains::volIndexToDb(const VolumeCurvePoint *curve, int indexMin, int indexMax, int indexInUi)
    {
        // the volume index in the UI is relative to the min and max volume indices for this stream type
        int nbSteps = 1 + curve[Volume::VOLMAX].mIndex - curve[Volume::VOLMIN].mIndex;
        int volIdx = (nbSteps * (indexInUi - indexMin)) / (indexMax - indexMin);
    
        // find what part of the curve this index volume belongs to, or if it's out of bounds
        int segment = 0;
        if (volIdx < curve[Volume::VOLMIN].mIndex) {         // out of bounds
            return VOLUME_MIN_DB;
        } else if (volIdx < curve[Volume::VOLKNEE1].mIndex) {
            segment = 0;
        } else if (volIdx < curve[Volume::VOLKNEE2].mIndex) {
            segment = 1;
        } else if (volIdx <= curve[Volume::VOLMAX].mIndex) {
            segment = 2;
        } else {                                                               // out of bounds
            return 0.0f;
        }
    
        // linear interpolation in the attenuation table in dB
        float decibels = curve[segment].mDBAttenuation +
                ((float)(volIdx - curve[segment].mIndex)) *
                    ( (curve[segment+1].mDBAttenuation -
                            curve[segment].mDBAttenuation) /
                        ((float)(curve[segment+1].mIndex -
                                curve[segment].mIndex)) );
    
        ALOGVV("VOLUME vol index=[%d %d %d], dB=[%.1f %.1f %.1f]",
                curve[segment].mIndex, volIdx,
                curve[segment+1].mIndex,
                curve[segment].mDBAttenuation,
                decibels,
                curve[segment+1].mDBAttenuation);
    
        return decibels;
    }
    

    Db值都是配置在audio_policy_volumes.xml中的。AOSP的

    frameworks/av/services/audiopolicy/config/audio_policy_volumes.xml
    

    安装流和设备分类来区分,比如,耳机的通话音量:

        <volume stream="AUDIO_STREAM_VOICE_CALL" deviceCategory="DEVICE_CATEGORY_HEADSET">
            <point>0,-4200</point>
            <point>33,-2800</point>
            <point>66,-1400</point>
            <point>100,0</point>
        </volume>
    

    除了直接定义值,还可以引用其他的,比如耳机的媒体音量,DEFAULT_MEDIA_VOLUME_CURVE。

        <volume stream="AUDIO_STREAM_MUSIC" deviceCategory="DEVICE_CATEGORY_HEADSET"
                                            ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
    

    DEFAULT_MEDIA_VOLUME_CURVE在另外已给表中:

    * frameworks/av/services/audiopolicy/config/default_volume_tables.xml
    
        <reference name="DEFAULT_MEDIA_VOLUME_CURVE">
        <!-- Default Media reference Volume Curve -->
            <point>1,-5800</point>
            <point>20,-4000</point>
            <point>60,-1700</point>
            <point>100,0</point>
        </reference>
    

    所以,我们调节音量时,根据音量的index,来转为对应的db,最终生效的是db。很多用户反馈上面音量调的很大了,但是实际的声音还是小,可能就调调整一下这里的db配置了。

    音量生效

    计算后的Db值通过setVolume函数设置给output

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

    函数如下:

    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;
    }
    
    • 先将音量值保存到Descriptor中
    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;
    }
    

    每个output都是安装流类型来保存的mCurVolume[stream]

    • 通过mClientInterface的setStreamVolume接口
    * frameworks/av/services/audiopolicy/service/AudioPolicyClientImpl.cpp
    
    status_t AudioPolicyService::AudioPolicyClient::setStreamVolume(audio_stream_type_t stream,
                         float volume, audio_io_handle_t output,
                         int delay_ms)
    {
        return mAudioPolicyService->setStreamVolume(stream, volume, output,
                                                   delay_ms);
    }
    

    AudioPolicyService通过AudioCommandThread,传给AudioManager

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

    对应的命令:SET_VOLUME

    bool AudioPolicyService::AudioCommandThread::threadLoop()
    {
        nsecs_t waitTime = -1;
    
        mLock.lock();
        while (!exitPending())
        {
            sp<AudioPolicyService> svc;
            while (!mAudioCommands.isEmpty() && !exitPending()) {
    ... ...
                    case SET_VOLUME: {
                        VolumeData *data = (VolumeData *)command->mParam.get();
                        ALOGV("AudioCommandThread() processing set volume stream %d, \
                                volume %f, output %d", data->mStream, data->mVolume, data->mIO);
                        command->mStatus = AudioSystem::setStreamVolume(data->mStream,
                                                                        data->mVolume,
                                                                        data->mIO);
                        }break;
    

    最终还是通过AudioSystem的接口来完成:

    status_t AudioSystem::setStreamVolume(audio_stream_type_t stream, float value,
            audio_io_handle_t output)
    {
        if (uint32_t(stream) >= AUDIO_STREAM_CNT) return BAD_VALUE;
        const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
        if (af == 0) return PERMISSION_DENIED;
        af->setStreamVolume(stream, value, output);
        return NO_ERROR;
    }
    

    AudioFlinger的setStreamVolume函数如下:

    status_t AudioFlinger::setStreamVolume(audio_stream_type_t stream, float value,
            audio_io_handle_t output)
    {
        ALOGI("setStreamVolume: stream %d, value %f, output %d", stream, value, output);
        // 权限
        if (!settingsAllowed()) {
            return PERMISSION_DENIED;
        }
    
        // 流类型
        status_t status = checkStreamType(stream);
        if (status != NO_ERROR) {
            return status;
        }
        ALOG_ASSERT(stream != AUDIO_STREAM_PATCH, "attempt to change AUDIO_STREAM_PATCH volume");
    
        AutoMutex lock(mLock);
        Vector<VolumeInterface *> volumeInterfaces;
        //获取volumeInterface
        if (output != AUDIO_IO_HANDLE_NONE) {
            VolumeInterface *volumeInterface = getVolumeInterface_l(output);
            if (volumeInterface == NULL) {
                return BAD_VALUE;
            }
            volumeInterfaces.add(volumeInterface);
        }
    
        // 保存音量Db值
        mStreamTypes[stream].volume = value;
    
        if (volumeInterfaces.size() == 0) {
            volumeInterfaces = getAllVolumeInterfaces_l();
        }
        // 设置音量值
        for (size_t i = 0; i < volumeInterfaces.size(); i++) {
            volumeInterfaces[i]->setStreamVolume(stream, value);
        }
    
        return NO_ERROR;
    }
    

    VolumeInterface 主要用以设置音量,PlaybackThread和MmapPlaybackThread实现VolumeInterface具体的接口:

    class VolumeInterface {
     public:
    
        virtual ~VolumeInterface() {}
    
        virtual void        setMasterVolume(float value) = 0;
        virtual void        setMasterMute(bool muted) = 0;
        virtual void        setStreamVolume(audio_stream_type_t stream, float value) = 0;
        virtual void        setStreamMute(audio_stream_type_t stream, bool muted) = 0;
        virtual float       streamVolume(audio_stream_type_t stream) const = 0;
    
    };
    

    我们来看看PlaybackThread的setStreamVolume函数:

    void AudioFlinger::PlaybackThread::setStreamVolume(audio_stream_type_t stream, float value)
    {
        Mutex::Autolock _l(mLock);
        size_t size = mEffectChains.size();
        mStreamTypes[stream].volume = value;
        for (size_t i = 0; i < size; i++) {
            mEffectChains[i]->setStreamVolume_l(stream, value);
        }
        broadcast_l();
    }
    

    PlaybackThread将音量值保存下来了,并设置到音效中。

    OK,到此,都全是设置音量的过程,那么是在什么地方生效的呢?

    对于MixerThread来说,是在这里生效的,音量值最终会被混音,设置到数据流中。

    AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTracks_l(
            Vector< sp<Track> > *tracksToRemove)
    {
    ... ...
                // 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
                // read original volumes with volume control
                float typeVolume = mStreamTypes[track->streamType()].volume;
                float v = masterVolume * typeVolume;
    
                if (track->isPausing() || mStreamTypes[track->streamType()].mute) {
                    vl = vr = 0;
                    vlf = vrf = vaf = 0.;
                    if (track->isPausing()) {
                        track->setPaused();
                    }
                } else {
                    sp<AudioTrackServerProxy> proxy = track->mAudioTrackServerProxy;
                    gain_minifloat_packed_t vlr = proxy->getVolumeLR();
                    vlf = float_from_gain(gain_minifloat_unpack_left(vlr));
                    vrf = float_from_gain(gain_minifloat_unpack_right(vlr));
                    // track volumes come from shared memory, so can't be trusted and must be clamped
                    if (vlf > GAIN_FLOAT_UNITY) {
                        ALOGV("Track left volume out of range: %.3g", vlf);
                        vlf = GAIN_FLOAT_UNITY;
                    }
                    if (vrf > GAIN_FLOAT_UNITY) {
                        ALOGV("Track right volume out of range: %.3g", vrf);
                        vrf = GAIN_FLOAT_UNITY;
                    }
                    const float vh = track->getVolumeHandler()->getVolume(
                            track->mAudioTrackServerProxy->framesReleased()).first;
                    // now apply the master volume and stream type volume and shaper volume
                    vlf *= v * vh;
                    vrf *= v * vh;
                    // assuming master volume and stream type volume each go up to 1.0,
                    // then derive vl and vr as U8.24 versions for the effect chain
                    const float scaleto8_24 = MAX_GAIN_INT * MAX_GAIN_INT;
                    vl = (uint32_t) (scaleto8_24 * vlf);
                    vr = (uint32_t) (scaleto8_24 * vrf);
                    // vl and vr are now in U8.24 format
                    uint16_t sendLevel = proxy->getSendLevel_U4_12();
                    // send level comes from shared memory and so may be corrupt
                    if (sendLevel > MAX_GAIN_INT) {
                        ALOGV("Track send level out of range: %04X", sendLevel);
                        sendLevel = MAX_GAIN_INT;
                    }
                    // vaf is represented as [0.0, 1.0] float by rescaling sendLevel
                    vaf = v * sendLevel * (1. / MAX_GAIN_INT);
                }
    

    我们可以通过adb命令,将thread的各个流的音量都dump出来:

    $ adb shell dumpsys media.audio_flinger | grep "Stream volumes in dB"
      Stream volumes in dB: 0:-24, 1:-27, 2:-25, 3:-52, 4:0, 5:-27, 6:0, 7:-6, 8:-27, 9:0, 10:-47, 11:0, 12:0
      Stream volumes in dB: 0:-24, 1:-27, 2:-25, 3:-52, 4:0, 5:-27, 6:0, 7:-6, 8:-27, 9:0, 10:-47, 11:0, 12:0
      Stream volumes in dB: 0:-24, 1:-27, 2:-25, 3:-52, 4:0, 5:-27, 6:0, 7:-6, 8:-27, 9:0, 10:-47, 11:0, 12:0
    

    相关文章

      网友评论

        本文标题:Android平台音量调节(二)Native的流程处理

        本文链接:https://www.haomeiwen.com/subject/eeqmyftx.html