Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a8b28250 authored by Eric Laurent's avatar Eric Laurent Committed by Android (Google) Code Review
Browse files

Merge "audio policy: improve accessibility volume" into nyc-dev

parents 0c07db6e 28d09f06
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -142,6 +142,8 @@ routing_strategy Engine::ManagerInterfaceImpl::getStrategyForUsage(audio_usage_t
{
    const SwAudioOutputCollection &outputs = mPolicyEngine->mApmObserver->getOutputs();

    //FIXME: getStrategyForUsage() should return STRATEGY_ACCESSIBILITY and getDeviceForStrategy()
    // should be implemented accordingly for STRATEGY_ACCESSIBILITY
    if (usage == AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY &&
            (outputs.isStreamActive(AUDIO_STREAM_RING) ||
             outputs.isStreamActive(AUDIO_STREAM_ALARM))) {
+44 −21
Original line number Diff line number Diff line
@@ -195,18 +195,9 @@ routing_strategy Engine::getStrategyForStream(audio_stream_type_t stream)

routing_strategy Engine::getStrategyForUsage(audio_usage_t usage)
{
    const SwAudioOutputCollection &outputs = mApmObserver->getOutputs();

    // usage to strategy mapping
    switch (usage) {
    case AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY:
        if (outputs.isStreamActive(AUDIO_STREAM_RING) ||
                outputs.isStreamActive(AUDIO_STREAM_ALARM)) {
            return STRATEGY_SONIFICATION;
        }
        if (isInCall()) {
            return STRATEGY_PHONE;
        }
        return STRATEGY_ACCESSIBILITY;

    case AUDIO_USAGE_MEDIA:
@@ -245,6 +236,17 @@ audio_devices_t Engine::getDeviceForStrategy(routing_strategy strategy) const

    const SwAudioOutputCollection &outputs = mApmObserver->getOutputs();

    return getDeviceForStrategyInt(strategy, (DeviceVector&)availableOutputDevices,
                                   availableInputDevices, outputs);
}



audio_devices_t Engine::getDeviceForStrategyInt(routing_strategy strategy,
                                                DeviceVector &availableOutputDevices,
                                                const DeviceVector &availableInputDevices,
                                                const SwAudioOutputCollection &outputs) const
{
    uint32_t device = AUDIO_DEVICE_NONE;
    uint32_t availableOutputDevicesType = availableOutputDevices.types();

@@ -260,14 +262,16 @@ audio_devices_t Engine::getDeviceForStrategy(routing_strategy strategy) const

    case STRATEGY_SONIFICATION_RESPECTFUL:
        if (isInCall()) {
            device = getDeviceForStrategy(STRATEGY_SONIFICATION);
            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 = getDeviceForStrategy(STRATEGY_SONIFICATION);
            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) &&
@@ -275,12 +279,15 @@ audio_devices_t Engine::getDeviceForStrategy(routing_strategy strategy) const
                device |= AUDIO_DEVICE_OUT_SPEAKER_SAFE;
                device &= ~AUDIO_DEVICE_OUT_SPEAKER;
            }
        } else if (outputs.isStreamActive(AUDIO_STREAM_MUSIC, SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY)) {
        } else if (outputs.isStreamActive(
                                AUDIO_STREAM_MUSIC, SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY)) {
            // while media is playing (or has recently played), use the same device
            device = getDeviceForStrategy(STRATEGY_MEDIA);
            device = getDeviceForStrategyInt(
                    STRATEGY_MEDIA, availableOutputDevices, availableInputDevices, outputs);
        } else {
            // when media is not playing anymore, fall back on the sonification behavior
            device = getDeviceForStrategy(STRATEGY_SONIFICATION);
            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) &&
@@ -294,7 +301,8 @@ audio_devices_t Engine::getDeviceForStrategy(routing_strategy strategy) const
    case STRATEGY_DTMF:
        if (!isInCall()) {
            // when off call, DTMF strategy follows the same rules as MEDIA strategy
            device = getDeviceForStrategy(STRATEGY_MEDIA);
            device = getDeviceForStrategyInt(
                    STRATEGY_MEDIA, availableOutputDevices, availableInputDevices, outputs);
            break;
        }
        // when in call, DTMF and PHONE strategies follow the same rules
@@ -321,8 +329,8 @@ audio_devices_t Engine::getDeviceForStrategy(routing_strategy strategy) const
                availableOutputDevicesType = availPrimaryOutputDevices;
            }
        }
        // for phone strategy, we first consider the forced use and then the available devices by order
        // of priority
        // for phone strategy, we first consider the forced use and then the available devices by
        // order of priority
        switch (mForceUse[AUDIO_POLICY_FORCE_FOR_COMMUNICATION]) {
        case AUDIO_POLICY_FORCE_BT_SCO:
            if (!isInCall() || strategy != STRATEGY_DTMF) {
@@ -408,7 +416,8 @@ audio_devices_t Engine::getDeviceForStrategy(routing_strategy strategy) const
        // If incall, just select the STRATEGY_PHONE device: The rest of the behavior is handled by
        // handleIncallSonification().
        if (isInCall()) {
            device = getDeviceForStrategy(STRATEGY_PHONE);
            device = getDeviceForStrategyInt(
                    STRATEGY_PHONE, availableOutputDevices, availableInputDevices, outputs);
            break;
        }
        // FALL THROUGH
@@ -429,7 +438,6 @@ audio_devices_t Engine::getDeviceForStrategy(routing_strategy strategy) const
        // The second device used for sonification is the same as the device used by media strategy
        // FALL THROUGH

    // FIXME: STRATEGY_ACCESSIBILITY and STRATEGY_REROUTING follow STRATEGY_MEDIA for now
    case STRATEGY_ACCESSIBILITY:
        if (strategy == STRATEGY_ACCESSIBILITY) {
            // do not route accessibility prompts to a digital output currently configured with a
@@ -443,20 +451,35 @@ audio_devices_t Engine::getDeviceForStrategy(routing_strategy strategy) const
                    availableOutputDevicesType = availableOutputDevices.types() & ~devices;
                }
            }
            availableOutputDevices =
                    availableOutputDevices.getDevicesFromType(availableOutputDevicesType);
            if (outputs.isStreamActive(AUDIO_STREAM_RING) ||
                    outputs.isStreamActive(AUDIO_STREAM_ALARM)) {
                return getDeviceForStrategyInt(
                    STRATEGY_SONIFICATION, availableOutputDevices, availableInputDevices, outputs);
            }
            if (isInCall()) {
                return getDeviceForStrategyInt(
                        STRATEGY_PHONE, availableOutputDevices, availableInputDevices, outputs);
            }
        }
        // For other cases, STRATEGY_ACCESSIBILITY behaves like STRATEGY_MEDIA
        // FALL THROUGH

    // FIXME: STRATEGY_REROUTING follow STRATEGY_MEDIA for now
    case STRATEGY_REROUTING:
    case STRATEGY_MEDIA: {
        uint32_t device2 = AUDIO_DEVICE_NONE;
        if (strategy != STRATEGY_SONIFICATION) {
            // no sonification on remote submix (e.g. WFD)
            if (availableOutputDevices.getDevice(AUDIO_DEVICE_OUT_REMOTE_SUBMIX, String8("0")) != 0) {
            if (availableOutputDevices.getDevice(AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
                                                 String8("0")) != 0) {
                device2 = availableOutputDevices.types() & AUDIO_DEVICE_OUT_REMOTE_SUBMIX;
            }
        }
        if (isInCall() && (strategy == STRATEGY_MEDIA)) {
            device = getDeviceForStrategy(STRATEGY_PHONE);
            device = getDeviceForStrategyInt(
                    STRATEGY_PHONE, availableOutputDevices, availableInputDevices, outputs);
            break;
        }
        if ((device2 == AUDIO_DEVICE_NONE) &&
+4 −0
Original line number Diff line number Diff line
@@ -125,6 +125,10 @@ private:
    routing_strategy getStrategyForStream(audio_stream_type_t stream);
    routing_strategy getStrategyForUsage(audio_usage_t usage);
    audio_devices_t getDeviceForStrategy(routing_strategy strategy) const;
    audio_devices_t getDeviceForStrategyInt(routing_strategy strategy,
                                            DeviceVector &availableOutputDevices,
                                            const DeviceVector &availableInputDevices,
                                            const SwAudioOutputCollection &outputs) const;
    audio_devices_t getDeviceForInputSource(audio_source_t inputSource) const;
    audio_mode_t mPhoneState;  /**< current phone state. */

+79 −60
Original line number Diff line number Diff line
@@ -1794,8 +1794,15 @@ void AudioPolicyManager::initStreamVolume(audio_stream_type_t stream,
{
    ALOGV("initStreamVolume() stream %d, min %d, max %d", stream , indexMin, indexMax);
    mVolumeCurves->initStreamVolume(stream, indexMin, indexMax);
    if (stream == AUDIO_STREAM_MUSIC) {
        mVolumeCurves->initStreamVolume(AUDIO_STREAM_ACCESSIBILITY, indexMin, indexMax);

    // initialize other private stream volumes which follow this one
    routing_strategy strategy = getStrategy(stream);
    for (int curStream = 0; curStream < AUDIO_STREAM_CNT; curStream++) {
        routing_strategy curStrategy = getStrategy((audio_stream_type_t)curStream);
        if (!strategiesMatchForvolume(strategy, curStrategy)) {
            continue;
        }
        mVolumeCurves->initStreamVolume((audio_stream_type_t)curStream, indexMin, indexMax);
    }
}

@@ -1823,38 +1830,43 @@ status_t AudioPolicyManager::setStreamVolumeIndex(audio_stream_type_t stream,
    if (device == AUDIO_DEVICE_OUT_DEFAULT) {
        mVolumeCurves->clearCurrentVolumeIndex(stream);
    }
    mVolumeCurves->addCurrentVolumeIndex(stream, device, index);

    // update volume on all outputs whose current device is also selected by the same
    // strategy as the device specified by the caller
    audio_devices_t selectedDevices = getDeviceForStrategy(getStrategy(stream), true /*fromCache*/);
    // it is possible that the requested device is not selected by the strategy (e.g an explicit
    // audio patch is active causing getDevicesForStream() to return this device. We must make
    // sure that the device passed is part of the devices considered when applying volume below.
    selectedDevices |= device;

    //FIXME: AUDIO_STREAM_ACCESSIBILITY volume follows AUDIO_STREAM_MUSIC for now
    audio_devices_t accessibilityDevice = AUDIO_DEVICE_NONE;
    if (stream == AUDIO_STREAM_MUSIC) {
        mVolumeCurves->addCurrentVolumeIndex(AUDIO_STREAM_ACCESSIBILITY, device, index);
        accessibilityDevice = getDeviceForStrategy(STRATEGY_ACCESSIBILITY, true /*fromCache*/);
    // update other private stream volumes which follow this one
    routing_strategy strategy = getStrategy(stream);
    for (int curStream = 0; curStream < AUDIO_STREAM_CNT; curStream++) {
        routing_strategy curStrategy = getStrategy((audio_stream_type_t)curStream);
        if (!strategiesMatchForvolume(strategy, curStrategy)) {
            continue;
        }
        mVolumeCurves->addCurrentVolumeIndex((audio_stream_type_t)curStream, device, index);
    }

    // update volume on all outputs whose current device is also selected by the same
    // strategy as the device specified by the caller
    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());
        if ((device == AUDIO_DEVICE_OUT_DEFAULT) || ((curDevice & selectedDevices) != 0)) {
            status_t volStatus = checkAndSetVolume(stream, index, desc, curDevice);
        for (int curStream = 0; curStream < AUDIO_STREAM_CNT; curStream++) {
            routing_strategy curStrategy = getStrategy((audio_stream_type_t)curStream);
            if (!strategiesMatchForvolume(strategy, curStrategy)) {
                continue;
            }
            audio_devices_t curStreamDevice = getDeviceForStrategy(curStrategy, true /*fromCache*/);
            // it is possible that the requested device is not selected by the strategy
            // (e.g an explicit audio patch is active causing getDevicesForStream()
            // to return this device. We must make sure that the device passed is part of the
            // devices considered when applying volume below.
            curStreamDevice |= device;

            if (((device == AUDIO_DEVICE_OUT_DEFAULT) ||
                    ((curDevice & curStreamDevice) != 0))) {
                status_t volStatus =
                        checkAndSetVolume((audio_stream_type_t)curStream, index, desc, curDevice);
                if (volStatus != NO_ERROR) {
                    status = volStatus;
                }
            }
        if ((accessibilityDevice != AUDIO_DEVICE_NONE) &&
                ((device == AUDIO_DEVICE_OUT_DEFAULT) || ((curDevice & accessibilityDevice) != 0)))
        {
            status_t volStatus = checkAndSetVolume(AUDIO_STREAM_ACCESSIBILITY,
                                                   index, desc, curDevice);
        }
    }
    return status;
@@ -1957,7 +1969,17 @@ status_t AudioPolicyManager::registerEffect(const effect_descriptor_t *desc,

bool AudioPolicyManager::isStreamActive(audio_stream_type_t stream, uint32_t inPastMs) const
{
    return mOutputs.isStreamActive(stream, inPastMs);
    bool active = false;
    routing_strategy strategy = getStrategy(stream);
    for (int curStream = 0; curStream < AUDIO_STREAM_CNT && !active; curStream++) {
        routing_strategy curStrategy = getStrategy((audio_stream_type_t)curStream);
        if (!strategiesMatchForvolume(strategy, curStrategy)) {
            continue;
        }
        active = mOutputs.isStreamActive((audio_stream_type_t)curStream, inPastMs);
    }

    return active;
}

bool AudioPolicyManager::isStreamActiveRemotely(audio_stream_type_t stream, uint32_t inPastMs) const
@@ -2838,7 +2860,7 @@ status_t AudioPolicyManager::connectAudioSource(const sp<AudioSourceDescriptor>&
    disconnectAudioSource(sourceDesc);

    routing_strategy strategy = (routing_strategy) getStrategyForAttr(&sourceDesc->mAttributes);
    audio_stream_type_t stream = audio_attributes_to_stream_type(&sourceDesc->mAttributes);
    audio_stream_type_t stream = streamTypefromAttributesInt(&sourceDesc->mAttributes);
    sp<DeviceDescriptor> srcDeviceDesc = sourceDesc->mDevice;

    audio_devices_t sinkDevice = getDeviceForStrategy(strategy, true);
@@ -2971,7 +2993,7 @@ status_t AudioPolicyManager::disconnectAudioSource(const sp<AudioSourceDescripto
    }
    removeAudioPatch(sourceDesc->mPatchDesc->mHandle);

    audio_stream_type_t stream = audio_attributes_to_stream_type(&sourceDesc->mAttributes);
    audio_stream_type_t stream = streamTypefromAttributesInt(&sourceDesc->mAttributes);
    sp<SwAudioOutputDescriptor> swOutputDesc = sourceDesc->mSwOutput.promote();
    if (swOutputDesc != 0) {
        stopSource(swOutputDesc, stream, false);
@@ -4170,10 +4192,10 @@ audio_devices_t AudioPolicyManager::getNewOutputDevice(const sp<AudioOutputDescr
    //      use device for strategy phone
    // 3: the strategy for enforced audible is active but not enforced on the output:
    //      use the device for strategy enforced audible
    // 4: the strategy accessibility is active on the output:
    //      use device for strategy accessibility
    // 5: the strategy sonification is active on the output:
    // 4: the strategy sonification is active on the output:
    //      use device for strategy sonification
    // 5: the strategy accessibility is active on the output:
    //      use device for strategy accessibility
    // 6: the strategy "respectful" sonification is active on the output:
    //      use device for strategy "respectful" sonification
    // 7: the strategy media is active on the output:
@@ -4190,10 +4212,10 @@ audio_devices_t AudioPolicyManager::getNewOutputDevice(const sp<AudioOutputDescr
        device = getDeviceForStrategy(STRATEGY_PHONE, fromCache);
    } else if (isStrategyActive(outputDesc, STRATEGY_ENFORCED_AUDIBLE)) {
        device = getDeviceForStrategy(STRATEGY_ENFORCED_AUDIBLE, fromCache);
    } else if (isStrategyActive(outputDesc, STRATEGY_ACCESSIBILITY)) {
        device = getDeviceForStrategy(STRATEGY_ACCESSIBILITY, fromCache);
    } else if (isStrategyActive(outputDesc, STRATEGY_SONIFICATION)) {
        device = getDeviceForStrategy(STRATEGY_SONIFICATION, fromCache);
    } else if (isStrategyActive(outputDesc, STRATEGY_ACCESSIBILITY)) {
        device = getDeviceForStrategy(STRATEGY_ACCESSIBILITY, fromCache);
    } else if (isStrategyActive(outputDesc, STRATEGY_SONIFICATION_RESPECTFUL)) {
        device = getDeviceForStrategy(STRATEGY_SONIFICATION_RESPECTFUL, fromCache);
    } else if (isStrategyActive(outputDesc, STRATEGY_MEDIA)) {
@@ -4229,6 +4251,13 @@ audio_devices_t AudioPolicyManager::getNewInputDevice(audio_io_handle_t input)
    return device;
}

bool AudioPolicyManager::strategiesMatchForvolume(routing_strategy strategy1,
                                                  routing_strategy strategy2) {
    return ((strategy1 == strategy2) ||
            ((strategy1 == STRATEGY_ACCESSIBILITY) && (strategy2 == STRATEGY_MEDIA)) ||
            ((strategy1 == STRATEGY_MEDIA) && (strategy2 == STRATEGY_ACCESSIBILITY)));
}

uint32_t AudioPolicyManager::getStrategyForStream(audio_stream_type_t stream) {
    return (uint32_t)getStrategy(stream);
}
@@ -4240,16 +4269,22 @@ audio_devices_t AudioPolicyManager::getDevicesForStream(audio_stream_type_t stre
    if (stream < (audio_stream_type_t) 0 || stream >= AUDIO_STREAM_PUBLIC_CNT) {
        return AUDIO_DEVICE_NONE;
    }
    audio_devices_t devices;
    audio_devices_t devices = AUDIO_DEVICE_NONE;
    routing_strategy strategy = getStrategy(stream);
    devices = getDeviceForStrategy(strategy, true /*fromCache*/);
    SortedVector<audio_io_handle_t> outputs = getOutputsForDevice(devices, mOutputs);
    for (int curStrategy = 0; curStrategy < NUM_STRATEGIES; curStrategy++) {
        if (!strategiesMatchForvolume(strategy, (routing_strategy)curStrategy)) {
            continue;
        }
        audio_devices_t curDevices =
                getDeviceForStrategy((routing_strategy)curStrategy, true /*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 (isStrategyActive(outputDesc, strategy)) {
            devices = outputDesc->device();
            break;
            if (isStrategyActive(outputDesc, (routing_strategy)curStrategy)) {
                curDevices |= outputDesc->device();
            }
        }
        devices |= curDevices;
    }

    /*Filter SPEAKER_SAFE out of results, as AudioService doesn't know about it
@@ -4361,15 +4396,8 @@ audio_devices_t AudioPolicyManager::getDeviceForStrategy(routing_strategy strate
    // the device = the device from the descriptor in the RouteMap, and exit.
    for (size_t routeIndex = 0; routeIndex < mOutputRoutes.size(); routeIndex++) {
        sp<SessionRoute> route = mOutputRoutes.valueAt(routeIndex);
        routing_strategy strat = getStrategy(route->mStreamType);
        // Special case for accessibility strategy which must follow any strategy it is
        // currently remapped to
        bool strategyMatch = (strat == strategy) ||
                             ((strategy == STRATEGY_ACCESSIBILITY) &&
                              ((mEngine->getStrategyForUsage(
                                      AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY) == strat) ||
                               (strat == STRATEGY_MEDIA)));
        if (strategyMatch && route->isActive()) {
        routing_strategy routeStrategy = getStrategy(route->mStreamType);
        if ((routeStrategy == strategy) && route->isActive()) {
            return route->mDeviceDescriptor->type();
        }
    }
@@ -5007,15 +5035,6 @@ audio_stream_type_t AudioPolicyManager::streamTypefromAttributesInt(const audio_
    case AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE:
        return AUDIO_STREAM_MUSIC;
    case AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY:
        if (isStreamActive(AUDIO_STREAM_ALARM)) {
            return AUDIO_STREAM_ALARM;
        }
        if (isStreamActive(AUDIO_STREAM_RING)) {
            return AUDIO_STREAM_RING;
        }
        if (isInCall()) {
            return AUDIO_STREAM_VOICE_CALL;
        }
        return AUDIO_STREAM_ACCESSIBILITY;
    case AUDIO_USAGE_ASSISTANCE_SONIFICATION:
        return AUDIO_STREAM_SYSTEM;
+3 −0
Original line number Diff line number Diff line
@@ -506,6 +506,9 @@ protected:
        void clearAudioSources(uid_t uid);


        static bool strategiesMatchForvolume(routing_strategy strategy1,
                                             routing_strategy strategy2);

        uid_t mUidCached;
        AudioPolicyClientInterface *mpClientInterface;  // audio policy client interface
        sp<SwAudioOutputDescriptor> mPrimaryOutput;     // primary output descriptor