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

Commit 6cd5f901 authored by Eric Laurent's avatar Eric Laurent
Browse files

Audio Policy Engine: fix in call routing (and other)

Routing rules for a given strategy can be adapted depending on the
context (e.g when in call or not) in order to make sure that concurrent
use cases do not use conflicting routes and that the highest priority
strategy prevails.

This strategy "remapping" must be done before we check possible
overrides of default routing for a given strategy by
setDevicesRoleForStrategy().

Commit cca11ce4 did partially address this but some cases were left aside.
This commit generalizes the behavior and moves all the strategy
remappings out of getDevicesForStrategyInt()

Bug: 183380877
Test: audio smoke tests
Change-Id: Ia272dd28ffd39441b62c9a262c38bf47dc44e7f0
parent c1992966
Loading
Loading
Loading
Loading
+67 −72
Original line number Diff line number Diff line
@@ -144,9 +144,10 @@ status_t Engine::setForceUse(audio_policy_force_use_t usage, audio_policy_forced

void Engine::filterOutputDevicesForStrategy(legacy_strategy strategy,
                                            DeviceVector& availableOutputDevices,
                                            const DeviceVector availableInputDevices,
                                            const SwAudioOutputCollection &outputs) const
{
    DeviceVector availableInputDevices = getApmObserver()->getAvailableInputDevices();

    switch (strategy) {
    case STRATEGY_SONIFICATION_RESPECTFUL: {
        if (!(isInCall() || outputs.isActiveLocally(toVolumeSource(AUDIO_STREAM_VOICE_CALL)))) {
@@ -204,9 +205,49 @@ void Engine::filterOutputDevicesForStrategy(legacy_strategy strategy,
    }
}

product_strategy_t Engine::remapStrategyFromContext(product_strategy_t strategy,
                                                 const SwAudioOutputCollection &outputs) const {
    auto legacyStrategy = mLegacyStrategyMap.find(strategy) != end(mLegacyStrategyMap) ?
                          mLegacyStrategyMap.at(strategy) : STRATEGY_NONE;

    if (isInCall()) {
        switch (legacyStrategy) {
        case STRATEGY_ACCESSIBILITY:
        case STRATEGY_DTMF:
        case STRATEGY_MEDIA:
        case STRATEGY_SONIFICATION:
        case STRATEGY_SONIFICATION_RESPECTFUL:
            legacyStrategy = STRATEGY_PHONE;
            break;

        default:
            return strategy;
        }
    } else {
        switch (legacyStrategy) {
        case STRATEGY_SONIFICATION_RESPECTFUL:
        case STRATEGY_SONIFICATION:
            if (outputs.isActiveLocally(toVolumeSource(AUDIO_STREAM_VOICE_CALL))) {
                legacyStrategy = STRATEGY_PHONE;
            }
            break;

        case STRATEGY_ACCESSIBILITY:
            if (outputs.isActive(toVolumeSource(AUDIO_STREAM_RING)) ||
                    outputs.isActive(toVolumeSource(AUDIO_STREAM_ALARM))) {
                legacyStrategy = STRATEGY_SONIFICATION;
            }
            break;

        default:
            return strategy;
        }
    }
    return getProductStrategyFromLegacy(legacyStrategy);
}

DeviceVector Engine::getDevicesForStrategyInt(legacy_strategy strategy,
                                              DeviceVector availableOutputDevices,
                                              DeviceVector availableInputDevices,
                                              const SwAudioOutputCollection &outputs) const
{
    DeviceVector devices;
@@ -217,32 +258,6 @@ DeviceVector Engine::getDevicesForStrategyInt(legacy_strategy strategy,
        devices = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_SPEAKER);
        break;

    case STRATEGY_SONIFICATION_RESPECTFUL:
        if (isInCall() || outputs.isActiveLocally(toVolumeSource(AUDIO_STREAM_VOICE_CALL))) {
            devices = getDevicesForStrategyInt(
                    STRATEGY_SONIFICATION, availableOutputDevices, availableInputDevices, outputs);
        } else {
            bool media_active_locally =
                    outputs.isActiveLocally(toVolumeSource(AUDIO_STREAM_MUSIC),
                                            SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY)
                    || outputs.isActiveLocally(
                        toVolumeSource(AUDIO_STREAM_ACCESSIBILITY),
                        SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY);
            devices = getDevicesForStrategyInt(STRATEGY_MEDIA,
                    availableOutputDevices,
                    availableInputDevices, outputs);
            // if no media is playing on the device, check for mandatory use of "safe" speaker
            // when media would have played on speaker, and the safe speaker path is available
            if (!media_active_locally) {
                devices.replaceDevicesByType(
                        AUDIO_DEVICE_OUT_SPEAKER,
                        availableOutputDevices.getDevicesFromType(
                                AUDIO_DEVICE_OUT_SPEAKER_SAFE));
            }
        }
        break;

    case STRATEGY_DTMF:
    case STRATEGY_PHONE: {
        devices = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_HEARING_AID);
        if (!devices.isEmpty()) break;
@@ -257,16 +272,6 @@ DeviceVector Engine::getDevicesForStrategyInt(legacy_strategy strategy,
    } break;

    case STRATEGY_SONIFICATION:

        // If incall, just select the STRATEGY_PHONE device
        if (isInCall() ||
                outputs.isActiveLocally(toVolumeSource(AUDIO_STREAM_VOICE_CALL))) {
            devices = getDevicesForStrategyInt(
                    STRATEGY_PHONE, availableOutputDevices, availableInputDevices, outputs);
            break;
        }
        FALLTHROUGH_INTENDED;

    case STRATEGY_ENFORCED_AUDIBLE:
        // strategy STRATEGY_ENFORCED_AUDIBLE uses same routing policy as STRATEGY_SONIFICATION
        // except:
@@ -314,22 +319,9 @@ DeviceVector Engine::getDevicesForStrategyInt(legacy_strategy strategy,
        // The second device used for sonification is the same as the device used by media strategy
        FALLTHROUGH_INTENDED;

    case STRATEGY_DTMF:
    case STRATEGY_ACCESSIBILITY:
        if (strategy == STRATEGY_ACCESSIBILITY) {
            if (outputs.isActive(toVolumeSource(AUDIO_STREAM_RING)) ||
                    outputs.isActive(toVolumeSource(AUDIO_STREAM_ALARM))) {
                return getDevicesForStrategyInt(
                    STRATEGY_SONIFICATION, availableOutputDevices, availableInputDevices, outputs);
            }
            if (isInCall()) {
                return getDevicesForStrategyInt(
                        STRATEGY_PHONE, availableOutputDevices, availableInputDevices, outputs);
            }
        }
        // For other cases, STRATEGY_ACCESSIBILITY behaves like STRATEGY_MEDIA
        FALLTHROUGH_INTENDED;

    // FIXME: STRATEGY_REROUTING follow STRATEGY_MEDIA for now
    case STRATEGY_SONIFICATION_RESPECTFUL:
    case STRATEGY_REROUTING:
    case STRATEGY_MEDIA: {
        DeviceVector devices2;
@@ -342,11 +334,6 @@ DeviceVector Engine::getDevicesForStrategyInt(legacy_strategy strategy,
                devices2.add(remoteSubmix);
            }
        }
        if (isInCall() && (strategy == STRATEGY_MEDIA)) {
            devices = getDevicesForStrategyInt(
                    STRATEGY_PHONE, availableOutputDevices, availableInputDevices, outputs);
            break;
        }

        if ((devices2.isEmpty()) &&
            (getForceUse(AUDIO_POLICY_FORCE_FOR_MEDIA) == AUDIO_POLICY_FORCE_SPEAKER)) {
@@ -394,9 +381,19 @@ DeviceVector Engine::getDevicesForStrategyInt(legacy_strategy strategy,
            devices.remove(devices.getDevicesFromType(AUDIO_DEVICE_OUT_SPEAKER));
        }

        // for STRATEGY_SONIFICATION:
        bool mediaActiveLocally =
                outputs.isActiveLocally(toVolumeSource(AUDIO_STREAM_MUSIC),
                                        SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY)
                || outputs.isActiveLocally(
                    toVolumeSource(AUDIO_STREAM_ACCESSIBILITY),
                    SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY);
        // - for STRATEGY_SONIFICATION:
        // if SPEAKER was selected, and SPEAKER_SAFE is available, use SPEAKER_SAFE instead
        if (strategy == STRATEGY_SONIFICATION) {
        // - for STRATEGY_SONIFICATION_RESPECTFUL:
        // if no media is playing on the device, check for mandatory use of "safe" speaker
        // when media would have played on speaker, and the safe speaker path is available
        if (strategy == STRATEGY_SONIFICATION
            || (strategy == STRATEGY_SONIFICATION_RESPECTFUL && !mediaActiveLocally)) {
            devices.replaceDevicesByType(
                    AUDIO_DEVICE_OUT_SPEAKER,
                    availableOutputDevices.getDevicesFromType(
@@ -649,22 +646,20 @@ DeviceVector Engine::getPreferredAvailableDevicesForProductStrategy(
    return preferredAvailableDevVec;
}


DeviceVector Engine::getDevicesForProductStrategy(product_strategy_t strategy) const {
    DeviceVector availableOutputDevices = getApmObserver()->getAvailableOutputDevices();
    const SwAudioOutputCollection& outputs = getApmObserver()->getOutputs();

    // Take context into account to remap product strategy before
    // checking preferred device for strategy and applying default routing rules
    strategy = remapStrategyFromContext(strategy, outputs);

    auto legacyStrategy = mLegacyStrategyMap.find(strategy) != end(mLegacyStrategyMap) ?
                          mLegacyStrategyMap.at(strategy) : STRATEGY_NONE;

    // When not in call, STRATEGY_DTMF follows STRATEGY_MEDIA
    if (!isInCall() && legacyStrategy == STRATEGY_DTMF) {
        legacyStrategy = STRATEGY_MEDIA;
        strategy = getProductStrategyFromLegacy(STRATEGY_MEDIA);
    }

    DeviceVector availableInputDevices = getApmObserver()->getAvailableInputDevices();
    const SwAudioOutputCollection& outputs = getApmObserver()->getOutputs();
    DeviceVector availableOutputDevices = getApmObserver()->getAvailableOutputDevices();

    filterOutputDevicesForStrategy(legacyStrategy, availableOutputDevices,
                                   availableInputDevices, outputs);
    filterOutputDevicesForStrategy(legacyStrategy, availableOutputDevices, outputs);

    // check if this strategy has a preferred device that is available,
    // if yes, give priority to it.
@@ -676,7 +671,7 @@ DeviceVector Engine::getDevicesForProductStrategy(product_strategy_t strategy) c

    return getDevicesForStrategyInt(legacyStrategy,
                                    availableOutputDevices,
                                    availableInputDevices, outputs);
                                    outputs);
}

DeviceVector Engine::getOutputDevicesForAttributes(const audio_attributes_t &attributes,
+3 −2
Original line number Diff line number Diff line
@@ -76,12 +76,13 @@ private:

    void filterOutputDevicesForStrategy(legacy_strategy strategy,
                                            DeviceVector& availableOutputDevices,
                                            const DeviceVector availableInputDevices,
                                            const SwAudioOutputCollection &outputs) const;

    product_strategy_t remapStrategyFromContext(product_strategy_t strategy,
                                            const SwAudioOutputCollection &outputs) const;

    DeviceVector getDevicesForStrategyInt(legacy_strategy strategy,
                                          DeviceVector availableOutputDevices,
                                          DeviceVector availableInputDevices,
                                          const SwAudioOutputCollection &outputs) const;

    DeviceVector getDevicesForProductStrategy(product_strategy_t strategy) const;