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

Commit 68e3f64e authored by Mikhail Naganov's avatar Mikhail Naganov Committed by Cherrypicker Worker
Browse files

Decouple the configuration from the AudioPolicyManager

Promote AudioPolicyConfig to a full class, not just a "view"
on the APM data. This allows separating initialization of
the APM config from the initialization of the APM itself.
Thus, the APM receives a fully initialized config upon
its creation, regardless of the way the config data has been
obtained.

Bug: 205884982
Test: atest audiopolicy_tests
Test: atest audiosystem_tests
Test: atest audio_health_tests
Test: m audiopolicy_fuzzer
(cherry picked from https://android-review.googlesource.com/q/commit:b0fbc1b40ddebb274b7a0bea811440507c357d82)
Merged-In: I334d16e762499a0292540e6abae4e177480d6235
Change-Id: I334d16e762499a0292540e6abae4e177480d6235
parent eafc269c
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@ cc_library_static {
        "src/AudioInputDescriptor.cpp",
        "src/AudioOutputDescriptor.cpp",
        "src/AudioPatch.cpp",
        "src/AudioPolicyConfig.cpp",
        "src/AudioPolicyMix.cpp",
        "src/AudioProfileVectorHelper.cpp",
        "src/AudioRoute.cpp",
+70 −126
Original line number Diff line number Diff line
@@ -16,62 +16,56 @@

#pragma once

#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>

#include <AudioPatch.h>
#include <DeviceDescriptor.h>
#include <IOProfile.h>
#include <HwModule.h>
#include <PolicyAudioPort.h>
#include <AudioInputDescriptor.h>
#include <AudioOutputDescriptor.h>
#include <AudioPolicyMix.h>
#include <EffectDescriptor.h>
#include <SoundTriggerSession.h>
#include <media/AudioProfile.h>
#include <error/Result.h>
#include <utils/StrongPointer.h>
#include <utils/RefBase.h>

namespace android {

// This class gathers together various bits of AudioPolicyManager
// configuration, which are usually filled out as a result of parsing
// the audio_policy_configuration.xml file.
// This class gathers together various bits of AudioPolicyManager configuration. It can be filled
// out either as a result of parsing the audio_policy_configuration.xml file, from the HAL data, or
// to default fallback data.
//
// Note that AudioPolicyConfig doesn't own some of the data,
// it simply proxies access to the fields of AudioPolicyManager
// class. Be careful about the fields that are references,
// e.g. 'mOutputDevices'. This also means that it's impossible
// to implement "deep copying" of this class without re-designing it.
class AudioPolicyConfig
// The data in this class is immutable once loaded, this is why a pointer to a const is returned
// from the factory methods. However, this does not prevent modifications of data bits that
// are held inside collections, for example, individual modules, devices, etc.
class AudioPolicyConfig : public RefBase
{
public:
    AudioPolicyConfig(HwModuleCollection &hwModules,
                      DeviceVector &outputDevices,
                      DeviceVector &inputDevices,
                      sp<DeviceDescriptor> &defaultOutputDevice)
        : mHwModules(hwModules),
          mOutputDevices(outputDevices),
          mInputDevices(inputDevices),
          mDefaultOutputDevice(defaultOutputDevice) {
        clear();
    }

    void clear() {
        mSource = {};
        mEngineLibraryNameSuffix = kDefaultEngineLibraryNameSuffix;
        mHwModules.clear();
        mOutputDevices.clear();
        mInputDevices.clear();
        mDefaultOutputDevice.clear();
        mIsSpeakerDrcEnabled = false;
        mIsCallScreenModeSupported = false;
        mSurroundFormats.clear();
    }
    // Surround formats, with an optional list of subformats that are equivalent from users' POV.
    using SurroundFormats = std::unordered_map<audio_format_t, std::unordered_set<audio_format_t>>;

    // The source used to indicate the default fallback configuration.
    static const constexpr char* const kDefaultConfigSource = "AudioPolicyConfig::setDefault";

    // Creates the default (fallback) configuration.
    static sp<const AudioPolicyConfig> createDefault();
    // Attempts to load the configuration from the XML file, falls back to default on failure.
    // If the XML file path is not provided, uses `audio_get_audio_policy_config_file` function.
    static sp<const AudioPolicyConfig> loadFromApmXmlConfigWithFallback(
            const std::string& xmlFilePath = "");
    // The factory method to use in APM tests which craft the configuration manually.
    static sp<AudioPolicyConfig> createWritableForTests();
    // The factory method to use in APM tests which use a custom XML file.
    static error::Result<sp<AudioPolicyConfig>> loadFromCustomXmlConfigForTests(
            const std::string& xmlFilePath);
    // The factory method to use in VTS tests. If the 'configPath' is empty,
    // it is determined automatically from the list of known config paths.
    static error::Result<sp<AudioPolicyConfig>> loadFromCustomXmlConfigForVtsTests(
            const std::string& configPath, const std::string& xmlFileName);

    ~AudioPolicyConfig() = default;

    const std::string& getSource() const {
        return mSource;
    }

    void setSource(const std::string& file) {
        mSource = file;
    }
@@ -79,16 +73,24 @@ public:
    const std::string& getEngineLibraryNameSuffix() const {
        return mEngineLibraryNameSuffix;
    }

    void setEngineLibraryNameSuffix(const std::string& suffix) {
        mEngineLibraryNameSuffix = suffix;
    }

    const HwModuleCollection& getHwModules() const { return mHwModules; }
    void setHwModules(const HwModuleCollection &hwModules)
    {
        mHwModules = hwModules;
    }

    const DeviceVector& getInputDevices() const
    {
        return mInputDevices;
    }
    const DeviceVector& getOutputDevices() const
    {
        return mOutputDevices;
    }
    void addDevice(const sp<DeviceDescriptor> &device)
    {
        if (audio_is_output_device(device->type())) {
@@ -97,128 +99,70 @@ public:
            mInputDevices.add(device);
        }
    }

    void addInputDevices(const DeviceVector &inputDevices)
    {
        mInputDevices.add(inputDevices);
    }

    void addOutputDevices(const DeviceVector &outputDevices)
    {
        mOutputDevices.add(outputDevices);
    }

    bool isSpeakerDrcEnabled() const { return mIsSpeakerDrcEnabled; }
    const sp<DeviceDescriptor>& getDefaultOutputDevice() const { return mDefaultOutputDevice; }
    void setDefaultOutputDevice(const sp<DeviceDescriptor> &defaultDevice)
    {
        mDefaultOutputDevice = defaultDevice;
    }

    bool isSpeakerDrcEnabled() const { return mIsSpeakerDrcEnabled; }
    void setSpeakerDrcEnabled(bool isSpeakerDrcEnabled)
    {
        mIsSpeakerDrcEnabled = isSpeakerDrcEnabled;
    }

    bool isCallScreenModeSupported() const { return mIsCallScreenModeSupported; }

    void setCallScreenModeSupported(bool isCallScreenModeSupported)
    {
        mIsCallScreenModeSupported = isCallScreenModeSupported;
    }


    const HwModuleCollection getHwModules() const { return mHwModules; }

    const DeviceVector &getInputDevices() const
    {
        return mInputDevices;
    }

    const DeviceVector &getOutputDevices() const
    {
        return mOutputDevices;
    }

    void setDefaultOutputDevice(const sp<DeviceDescriptor> &defaultDevice)
    {
        mDefaultOutputDevice = defaultDevice;
    }

    const sp<DeviceDescriptor> &getDefaultOutputDevice() const { return mDefaultOutputDevice; }

    void setDefault(void)
    {
        mSource = "AudioPolicyConfig::setDefault";
        mEngineLibraryNameSuffix = kDefaultEngineLibraryNameSuffix;
        mDefaultOutputDevice = new DeviceDescriptor(AUDIO_DEVICE_OUT_SPEAKER);
        mDefaultOutputDevice->addAudioProfile(AudioProfile::createFullDynamic(gDynamicFormat));
        sp<DeviceDescriptor> defaultInputDevice = new DeviceDescriptor(AUDIO_DEVICE_IN_BUILTIN_MIC);
        defaultInputDevice->addAudioProfile(AudioProfile::createFullDynamic(gDynamicFormat));
        sp<AudioProfile> micProfile = new AudioProfile(
                AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_MONO, 8000);
        defaultInputDevice->addAudioProfile(micProfile);
        mOutputDevices.add(mDefaultOutputDevice);
        mInputDevices.add(defaultInputDevice);

        sp<HwModule> module = new HwModule(AUDIO_HARDWARE_MODULE_ID_PRIMARY, 2 /*halVersionMajor*/);
        mHwModules.add(module);

        sp<OutputProfile> outProfile = new OutputProfile("primary");
        outProfile->addAudioProfile(
                new AudioProfile(AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO, 44100));
        outProfile->addSupportedDevice(mDefaultOutputDevice);
        outProfile->setFlags(AUDIO_OUTPUT_FLAG_PRIMARY);
        module->addOutputProfile(outProfile);

        sp<InputProfile> inProfile = new InputProfile("primary");
        inProfile->addAudioProfile(micProfile);
        inProfile->addSupportedDevice(defaultInputDevice);
        module->addInputProfile(inProfile);

        setDefaultSurroundFormats();
    }

    // Surround formats, with an optional list of subformats that are equivalent from users' POV.
    using SurroundFormats = std::unordered_map<audio_format_t, std::unordered_set<audio_format_t>>;

    const SurroundFormats &getSurroundFormats() const
    {
        return mSurroundFormats;
    }

    void setDefaultSurroundFormats();
    void setSurroundFormats(const SurroundFormats &surroundFormats)
    {
        mSurroundFormats = surroundFormats;
    }

    void setDefaultSurroundFormats()
    void setSurroundFormats(SurroundFormats &&surroundFormats)
    {
        mSurroundFormats = {
            {AUDIO_FORMAT_AC3, {}},
            {AUDIO_FORMAT_E_AC3, {}},
            {AUDIO_FORMAT_DTS, {}},
            {AUDIO_FORMAT_DTS_HD, {}},
            {AUDIO_FORMAT_DTS_HD_MA, {}},
            {AUDIO_FORMAT_DTS_UHD, {}},
            {AUDIO_FORMAT_DTS_UHD_P2, {}},
            {AUDIO_FORMAT_AAC_LC, {
                    AUDIO_FORMAT_AAC_HE_V1, AUDIO_FORMAT_AAC_HE_V2, AUDIO_FORMAT_AAC_ELD,
                    AUDIO_FORMAT_AAC_XHE}},
            {AUDIO_FORMAT_DOLBY_TRUEHD, {}},
            {AUDIO_FORMAT_E_AC3_JOC, {}},
            {AUDIO_FORMAT_AC4, {}}};
        mSurroundFormats = std::move(surroundFormats);
    }

    void setDefault();

private:
    friend class sp<AudioPolicyConfig>;

    static const constexpr char* const kDefaultEngineLibraryNameSuffix = "default";

    std::string mSource;
    std::string mEngineLibraryNameSuffix;
    HwModuleCollection &mHwModules; /**< Collection of Module, with Profiles, i.e. Mix Ports. */
    DeviceVector &mOutputDevices;
    DeviceVector &mInputDevices;
    sp<DeviceDescriptor> &mDefaultOutputDevice;
    AudioPolicyConfig() = default;

    void augmentData();
    status_t loadFromXml(const std::string& xmlFilePath, bool forVts);

    std::string mSource;  // Not kDefaultConfigSource. Empty source means an empty config.
    std::string mEngineLibraryNameSuffix = kDefaultEngineLibraryNameSuffix;
    HwModuleCollection mHwModules; /**< Collection of Module, with Profiles, i.e. Mix Ports. */
    DeviceVector mOutputDevices;
    DeviceVector mInputDevices;
    sp<DeviceDescriptor> mDefaultOutputDevice;
    // TODO: remove when legacy conf file is removed. true on devices that use DRC on the
    // DEVICE_CATEGORY_SPEAKER path to boost soft sounds, used to adjust volume curves accordingly.
    // Note: remove also speaker_drc_enabled from global configuration of XML config file.
    bool mIsSpeakerDrcEnabled;
    bool mIsCallScreenModeSupported;
    bool mIsSpeakerDrcEnabled = false;
    bool mIsCallScreenModeSupported = false;
    SurroundFormats mSurroundFormats;
};

+171 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2009 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#define LOG_TAG "APM_Config"

#include <AudioPolicyConfig.h>
#include <IOProfile.h>
#include <Serializer.h>
#include <media/AudioProfile.h>
#include <system/audio.h>
#include <system/audio_config.h>
#include <utils/Log.h>

namespace android {

// static
sp<const AudioPolicyConfig> AudioPolicyConfig::createDefault() {
    auto config = sp<AudioPolicyConfig>::make();
    config->setDefault();
    return config;
}

// static
sp<const AudioPolicyConfig> AudioPolicyConfig::loadFromApmXmlConfigWithFallback(
        const std::string& xmlFilePath) {
    const std::string filePath =
            xmlFilePath.empty() ? audio_get_audio_policy_config_file() : xmlFilePath;
    auto config = sp<AudioPolicyConfig>::make();
    if (status_t status = config->loadFromXml(filePath, false /*forVts*/); status == NO_ERROR) {
        return config;
    } else {
        return createDefault();
    }
}

// static
sp<AudioPolicyConfig> AudioPolicyConfig::createWritableForTests() {
    return sp<AudioPolicyConfig>::make();
}

// static
error::Result<sp<AudioPolicyConfig>> AudioPolicyConfig::loadFromCustomXmlConfigForTests(
        const std::string& xmlFilePath) {
    auto config = sp<AudioPolicyConfig>::make();
    if (status_t status = config->loadFromXml(xmlFilePath, false /*forVts*/); status == NO_ERROR) {
        return config;
    } else {
        return base::unexpected(status);
    }
}

// static
error::Result<sp<AudioPolicyConfig>> AudioPolicyConfig::loadFromCustomXmlConfigForVtsTests(
        const std::string& configPath, const std::string& xmlFileName) {
    auto filePath = configPath;
    if (filePath.empty()) {
        for (const auto& location : audio_get_configuration_paths()) {
            std::string path = location + '/' + xmlFileName;
            if (access(path.c_str(), F_OK) == 0) {
                filePath = location;
                break;
            }
        }
    }
    if (filePath.empty()) {
        ALOGE("Did not find a config file \"%s\" among known config paths", xmlFileName.c_str());
        return base::unexpected(BAD_VALUE);
    }
    auto config = sp<AudioPolicyConfig>::make();
    if (status_t status = config->loadFromXml(filePath + "/" + xmlFileName, true /*forVts*/);
            status == NO_ERROR) {
        return config;
    } else {
        return base::unexpected(status);
    }
}

void AudioPolicyConfig::augmentData() {
    // If microphones address is empty, set it according to device type
    for (size_t i = 0; i < mInputDevices.size(); i++) {
        if (mInputDevices[i]->address().empty()) {
            if (mInputDevices[i]->type() == AUDIO_DEVICE_IN_BUILTIN_MIC) {
                mInputDevices[i]->setAddress(AUDIO_BOTTOM_MICROPHONE_ADDRESS);
            } else if (mInputDevices[i]->type() == AUDIO_DEVICE_IN_BACK_MIC) {
                mInputDevices[i]->setAddress(AUDIO_BACK_MICROPHONE_ADDRESS);
            }
        }
    }
}

status_t AudioPolicyConfig::loadFromXml(const std::string& xmlFilePath, bool forVts) {
    if (xmlFilePath.empty()) {
        ALOGE("Audio policy configuration file name is empty");
        return BAD_VALUE;
    }
    status_t status = forVts ? deserializeAudioPolicyFileForVts(xmlFilePath.c_str(), this)
            : deserializeAudioPolicyFile(xmlFilePath.c_str(), this);
    if (status == NO_ERROR) {
        mSource = xmlFilePath;
        augmentData();
    } else {
        ALOGE("Could not load audio policy from the configuration file \"%s\": %d",
                xmlFilePath.c_str(), status);
    }
    return status;
}

void AudioPolicyConfig::setDefault() {
    mSource = kDefaultConfigSource;
    mEngineLibraryNameSuffix = kDefaultEngineLibraryNameSuffix;

    mDefaultOutputDevice = new DeviceDescriptor(AUDIO_DEVICE_OUT_SPEAKER);
    mDefaultOutputDevice->addAudioProfile(AudioProfile::createFullDynamic(gDynamicFormat));
    sp<DeviceDescriptor> defaultInputDevice = new DeviceDescriptor(AUDIO_DEVICE_IN_BUILTIN_MIC);
    defaultInputDevice->addAudioProfile(AudioProfile::createFullDynamic(gDynamicFormat));
    sp<AudioProfile> micProfile = new AudioProfile(
            AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_MONO, 8000);
    defaultInputDevice->addAudioProfile(micProfile);
    mOutputDevices.add(mDefaultOutputDevice);
    mInputDevices.add(defaultInputDevice);

    sp<HwModule> module = new HwModule(AUDIO_HARDWARE_MODULE_ID_PRIMARY, 2 /*halVersionMajor*/);
    mHwModules.add(module);

    sp<OutputProfile> outProfile = new OutputProfile("primary");
    outProfile->addAudioProfile(
            new AudioProfile(AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO, 44100));
    outProfile->addSupportedDevice(mDefaultOutputDevice);
    outProfile->setFlags(AUDIO_OUTPUT_FLAG_PRIMARY);
    module->addOutputProfile(outProfile);

    sp<InputProfile> inProfile = new InputProfile("primary");
    inProfile->addAudioProfile(micProfile);
    inProfile->addSupportedDevice(defaultInputDevice);
    module->addInputProfile(inProfile);

    setDefaultSurroundFormats();
    augmentData();
}

void AudioPolicyConfig::setDefaultSurroundFormats() {
    mSurroundFormats = {
        {AUDIO_FORMAT_AC3, {}},
        {AUDIO_FORMAT_E_AC3, {}},
        {AUDIO_FORMAT_DTS, {}},
        {AUDIO_FORMAT_DTS_HD, {}},
        {AUDIO_FORMAT_DTS_HD_MA, {}},
        {AUDIO_FORMAT_DTS_UHD, {}},
        {AUDIO_FORMAT_DTS_UHD_P2, {}},
        {AUDIO_FORMAT_AAC_LC, {
                AUDIO_FORMAT_AAC_HE_V1, AUDIO_FORMAT_AAC_HE_V2, AUDIO_FORMAT_AAC_ELD,
                AUDIO_FORMAT_AAC_XHE}},
        {AUDIO_FORMAT_DOLBY_TRUEHD, {}},
        {AUDIO_FORMAT_E_AC3_JOC, {}},
        {AUDIO_FORMAT_AC4, {}}};
}

} // namespace android
+1 −2
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@
#include <utils/StrongPointer.h>
#include <utils/Errors.h>
#include <utils/RefBase.h>
#include "IOProfile.h"
#include "Serializer.h"
#include "TypeConverter.h"

@@ -907,7 +908,6 @@ status_t deserializeAudioPolicyFile(const char *fileName, AudioPolicyConfig *con
{
    PolicySerializer serializer;
    status_t status = serializer.deserialize(fileName, config);
    if (status != OK) config->clear();
    return status;
}

@@ -915,7 +915,6 @@ status_t deserializeAudioPolicyFileForVts(const char *fileName, AudioPolicyConfi
{
    PolicySerializer serializer;
    status_t status = serializer.deserialize(fileName, config, true /*ignoreVendorExtensions*/);
    if (status != OK) config->clear();
    return status;
}

+12 −4
Original line number Diff line number Diff line
@@ -216,8 +216,9 @@ class AudioPolicyManagerFuzzer {
    virtual void process();

   protected:
    sp<AudioPolicyConfig> mConfig{AudioPolicyConfig::createWritableForTests()};
    std::unique_ptr<AudioPolicyManagerTestClient> mClient{new AudioPolicyManagerTestClient};
    std::unique_ptr<AudioPolicyTestManager> mManager{new AudioPolicyTestManager(mClient.get())};
    std::unique_ptr<AudioPolicyTestManager> mManager;
    FuzzedDataProvider *mFdp;
};

@@ -230,7 +231,10 @@ bool AudioPolicyManagerFuzzer::initialize() {
    }
    // init code
    SetUpManagerConfig();

    if (mConfig == nullptr) {
        return false;
    }
    mManager.reset(new AudioPolicyTestManager(mConfig, mClient.get()));
    if (mManager->initialize() != NO_ERROR) {
        return false;
    }
@@ -240,7 +244,7 @@ bool AudioPolicyManagerFuzzer::initialize() {
    return true;
}

void AudioPolicyManagerFuzzer::SetUpManagerConfig() { mManager->getConfig().setDefault(); }
void AudioPolicyManagerFuzzer::SetUpManagerConfig() { mConfig->setDefault(); }

bool AudioPolicyManagerFuzzer::getOutputForAttr(
    audio_port_handle_t *selectedDeviceId, audio_format_t format, audio_channel_mask_t channelMask,
@@ -408,7 +412,11 @@ std::string AudioPolicyManagerFuzzerWithConfigurationFile::getConfigFile() {
}

void AudioPolicyManagerFuzzerWithConfigurationFile::SetUpManagerConfig() {
    deserializeAudioPolicyFile(getConfigFile().c_str(), &mManager->getConfig());
    const std::string configFilePath = getConfigFile();
    auto result = AudioPolicyConfig::loadFromCustomXmlConfigForTests(configFilePath);
    mConfig = result.ok() ? mConfig = result.value() : nullptr;
    ALOGE_IF(!result.ok(), "%s: Failed to deserialize \"%s\": %d",
            __func__, configFilePath.c_str(), result.error());
}

void AudioPolicyManagerFuzzerWithConfigurationFile::traverseAndFuzzXML(xmlDocPtr pDoc,
Loading