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

Commit 5740f08a authored by jiabin's avatar jiabin
Browse files

Add AudioPortFoundation, AudioPortBase and AudioPortConfigBase.

The purpose of this change is to make a generic AudioPort class that
could be used by vendor.
1. Add AudioPortFoundation and AudioPortBase. AudioPortFoundation
contains generic members of an audio port. AudioPortBase is a template
class that derives from AudioPortFoundation. It takes audio profile
vector as a template parameters. That makes it more feasible to use
customized audio profile stuff as needed. In audio policy, AudioPort
derives from AudioPortBase and contain policy related stuff.
2. Add AudioPortConfigBase. AudioPortConfigBase contains generic members
of an audio port config. AudioPortConfig derives from AudioPortConfigBase
and contains policy related stuff.
3. Use std::string instead of String8 in AudioPort and AudioPortConfig.

Bug: 135621476
Test: CTS for AudioRecord, AudioTrack, AudioManager, RoutingTest
Test: audiopolicy_tests, AudioServiceHostTest
audio smoke test
Test: dumpsys media.audio_policy
Change-Id: I05611b7067c18006660de2c678acd56bdd34010a
parent ea87a0ce
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -10,6 +10,7 @@ cc_library_shared {

    srcs: [
        "AudioGain.cpp",
        "AudioPortBase.cpp",
        "AudioProfile.cpp",
    ],

+87 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 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.
 */

#include <algorithm>

#include <android-base/stringprintf.h>
#include <media/AudioPortBase.h>
#include <utils/Log.h>

namespace android {

void AudioPortFoundation::toAudioPort(struct audio_port *port) const {
    // TODO: update this function once audio_port structure reflects the new profile definition.
    // For compatibility reason: flatening the AudioProfile into audio_port structure.
    FormatSet flatenedFormats;
    SampleRateSet flatenedRates;
    ChannelMaskSet flatenedChannels;
    for (const auto& profile : *getAudioProfileVectorBase()) {
        if (profile->isValid()) {
            audio_format_t formatToExport = profile->getFormat();
            const SampleRateSet &ratesToExport = profile->getSampleRates();
            const ChannelMaskSet &channelsToExport = profile->getChannels();

            flatenedFormats.insert(formatToExport);
            flatenedRates.insert(ratesToExport.begin(), ratesToExport.end());
            flatenedChannels.insert(channelsToExport.begin(), channelsToExport.end());

            if (flatenedRates.size() > AUDIO_PORT_MAX_SAMPLING_RATES ||
                    flatenedChannels.size() > AUDIO_PORT_MAX_CHANNEL_MASKS ||
                    flatenedFormats.size() > AUDIO_PORT_MAX_FORMATS) {
                ALOGE("%s: bailing out: cannot export profiles to port config", __func__);
                return;
            }
        }
    }
    port->role = mRole;
    port->type = mType;
    strlcpy(port->name, mName.c_str(), AUDIO_PORT_MAX_NAME_LEN);
    port->num_sample_rates = flatenedRates.size();
    port->num_channel_masks = flatenedChannels.size();
    port->num_formats = flatenedFormats.size();
    std::copy(flatenedRates.begin(), flatenedRates.end(), port->sample_rates);
    std::copy(flatenedChannels.begin(), flatenedChannels.end(), port->channel_masks);
    std::copy(flatenedFormats.begin(), flatenedFormats.end(), port->formats);

    ALOGV("AudioPort::toAudioPort() num gains %zu", mGains.size());

    port->num_gains = std::min(mGains.size(), (size_t) AUDIO_PORT_MAX_GAINS);
    for (size_t i = 0; i < port->num_gains; i++) {
        port->gains[i] = mGains[i]->getGain();
    }
}

void AudioPortFoundation::dump(std::string *dst, int spaces, bool verbose) const {
    if (!mName.empty()) {
        dst->append(base::StringPrintf("%*s- name: %s\n", spaces, "", mName.c_str()));
    }
    if (verbose) {
        std::string profilesStr;
        getAudioProfileVectorBase()->dump(&profilesStr, spaces);
        dst->append(profilesStr);

        if (mGains.size() != 0) {
            dst->append(base::StringPrintf("%*s- gains:\n", spaces, ""));
            for (size_t i = 0; i < mGains.size(); i++) {
                std::string gainStr;
                mGains[i]->dump(&gainStr, spaces + 2, i);
                dst->append(gainStr);
            }
        }
    }
}

}
 No newline at end of file
+63 −114
Original line number Diff line number Diff line
/*
 * Copyright (C) 2015 The Android Open Source Project
 * Copyright (C) 2019 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.
@@ -13,113 +13,57 @@
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#if 0

#pragma once

#include "AudioCollections.h"
#include "AudioProfile.h"
#include "HandleGenerator.h"
#include <string>

#include <media/AudioGain.h>
#include <utils/String8.h>
#include <utils/Vector.h>
#include <utils/RefBase.h>
#include <media/AudioProfile.h>
#include <utils/Errors.h>
#include <utils/RefBase.h>
#include <system/audio.h>
#include <cutils/config_utils.h>

namespace android {

class HwModule;
class AudioRoute;

class AudioPort : public virtual RefBase, private HandleGenerator<audio_port_handle_t>
class AudioPortFoundation : public virtual RefBase
{
public:
    AudioPort(const String8& name, audio_port_type_t type,  audio_port_role_t role) :
        mName(name), mType(type), mRole(role), mFlags(AUDIO_OUTPUT_FLAG_NONE) {}
    AudioPortFoundation(const std::string& name, audio_port_type_t type,  audio_port_role_t role) :
            mName(name), mType(type), mRole(role) {}

    virtual ~AudioPort() {}
    virtual ~AudioPortFoundation() = default;

    void setName(const String8 &name) { mName = name; }
    const String8 &getName() const { return mName; }
    void setName(const std::string &name) { mName = name; }
    const std::string &getName() const { return mName; }

    audio_port_type_t getType() const { return mType; }
    audio_port_role_t getRole() const { return mRole; }

    virtual const String8 getTagName() const = 0;
    virtual const std::string getTagName() const = 0;

    void setGains(const AudioGains &gains) { mGains = gains; }
    const AudioGains &getGains() const { return mGains; }

    virtual void setFlags(uint32_t flags)
    {
        //force direct flag if offload flag is set: offloading implies a direct output stream
        // and all common behaviors are driven by checking only the direct flag
        // this should normally be set appropriately in the policy configuration file
        if (mRole == AUDIO_PORT_ROLE_SOURCE && (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) {
            flags |= AUDIO_OUTPUT_FLAG_DIRECT;
        }
        mFlags = flags;
    }
    uint32_t getFlags() const { return mFlags; }

    virtual void attach(const sp<HwModule>& module);
    virtual void detach();
    bool isAttached() { return mModule != 0; }

    // Audio port IDs are in a different namespace than AudioFlinger unique IDs
    static audio_port_handle_t getNextUniqueId();

    virtual void toAudioPort(struct audio_port *port) const;

    virtual void importAudioPort(const sp<AudioPort>& port, bool force = false);

    void addAudioProfile(const sp<AudioProfile> &profile) { mProfiles.add(profile); }

    void setAudioProfiles(const AudioProfileVector &profiles) { mProfiles = profiles; }
    AudioProfileVector &getAudioProfiles() { return mProfiles; }

    bool hasValidAudioProfile() const { return mProfiles.hasValidProfile(); }

    bool hasDynamicAudioProfile() const { return mProfiles.hasDynamicProfile(); }

    // searches for an exact match
    virtual status_t checkExactAudioProfile(const struct audio_port_config *config) const;

    // searches for a compatible match, currently implemented for input
    // parameters are input|output, returned value is the best match.
    status_t checkCompatibleAudioProfile(uint32_t &samplingRate,
                                         audio_channel_mask_t &channelMask,
                                         audio_format_t &format) const
    {
        return mProfiles.checkCompatibleProfile(samplingRate, channelMask, format, mType, mRole);
    virtual AudioProfileVectorBase* getAudioProfileVectorBase() const = 0;
    virtual void addAudioProfile(const sp<AudioProfile> &profile) {
        getAudioProfileVectorBase()->add(profile);
    }
    virtual void clearAudioProfiles() {
        getAudioProfileVectorBase()->clearProfiles();
    }

    void clearAudioProfiles() { return mProfiles.clearProfiles(); }

    status_t checkGain(const struct audio_gain_config *gainConfig, int index) const;

    void pickAudioProfile(uint32_t &samplingRate,
                          audio_channel_mask_t &channelMask,
                          audio_format_t &format) const;

    static const audio_format_t sPcmFormatCompareTable[];

    static int compareFormats(audio_format_t format1, audio_format_t format2);

    // Used to select an audio HAL output stream with a sample format providing the
    // less degradation for a given AudioTrack sample format.
    static bool isBetterFormatMatch(audio_format_t newFormat,
                                    audio_format_t currentFormat,
                                    audio_format_t targetFormat);
    static uint32_t formatDistance(audio_format_t format1,
                                   audio_format_t format2);
    static const uint32_t kFormatDistanceMax = 4;
    bool hasValidAudioProfile() const { return getAudioProfileVectorBase()->hasValidProfile(); }

    audio_module_handle_t getModuleHandle() const;
    uint32_t getModuleVersionMajor() const;
    const char *getModuleName() const;
    sp<HwModule> getModule() const { return mModule; }
    status_t checkGain(const struct audio_gain_config *gainConfig, int index) const {
        if (index < 0 || (size_t)index >= mGains.size()) {
            return BAD_VALUE;
        }
        return mGains[index]->checkConfig(gainConfig);
    }

    bool useInputChannelMask() const
    {
@@ -127,55 +71,60 @@ public:
                ((mType == AUDIO_PORT_TYPE_MIX) && (mRole == AUDIO_PORT_ROLE_SINK));
    }

    inline bool isDirectOutput() const
    {
        return (mType == AUDIO_PORT_TYPE_MIX) && (mRole == AUDIO_PORT_ROLE_SOURCE) &&
                (mFlags & (AUDIO_OUTPUT_FLAG_DIRECT | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD));
    }
    void dump(std::string *dst, int spaces, bool verbose = true) const;

    void addRoute(const sp<AudioRoute> &route) { mRoutes.add(route); }
    const AudioRouteVector &getRoutes() const { return mRoutes; }
    AudioGains mGains; // gain controllers
protected:
    std::string  mName;
    audio_port_type_t mType;
    audio_port_role_t mRole;
};

    void dump(String8 *dst, int spaces, bool verbose = true) const;
template <typename ProfileVector,
          typename = typename std::enable_if<std::is_base_of<
                  AudioProfileVectorBase, ProfileVector>::value>::type>
class AudioPortBase : public AudioPortFoundation
{
public:
    AudioPortBase(const std::string& name, audio_port_type_t type,  audio_port_role_t role) :
            AudioPortFoundation(name, type, role) {}

    void log(const char* indent) const;
    virtual ~AudioPortBase() {}

    AudioGains mGains; // gain controllers
    AudioProfileVectorBase* getAudioProfileVectorBase() const override {
        return static_cast<AudioProfileVectorBase*>(const_cast<ProfileVector*>(&mProfiles));
    }

private:
    void pickChannelMask(audio_channel_mask_t &channelMask,
                         const ChannelMaskSet &channelMasks) const;
    void pickSamplingRate(uint32_t &rate, const SampleRateSet &samplingRates) const;
    void addAudioProfile(const sp<AudioProfile> &profile) override { mProfiles.add(profile); }
    void clearAudioProfiles() override { return mProfiles.clearProfiles(); }

    sp<HwModule> mModule;                 // audio HW module exposing this I/O stream
    String8  mName;
    audio_port_type_t mType;
    audio_port_role_t mRole;
    uint32_t mFlags; // attribute flags mask (e.g primary output, direct output...).
    AudioProfileVector mProfiles; // AudioProfiles supported by this port (format, Rates, Channels)
    AudioRouteVector mRoutes; // Routes involving this port
    void setAudioProfiles(const ProfileVector &profiles) { mProfiles = profiles; }
    ProfileVector &getAudioProfiles() { return mProfiles; }

protected:
    ProfileVector mProfiles; // AudioProfiles supported by this port (format, Rates, Channels)
};

class AudioPortConfig : public virtual RefBase

class AudioPortConfigBase : public virtual RefBase
{
public:
    status_t applyAudioPortConfig(const struct audio_port_config *config,
                                  struct audio_port_config *backupConfig = NULL);
    virtual ~AudioPortConfigBase() = default;

    virtual status_t applyAudioPortConfig(const struct audio_port_config *config,
                                          struct audio_port_config *backupConfig = NULL) = 0;
    virtual void toAudioPortConfig(struct audio_port_config *dstConfig,
                                   const struct audio_port_config *srcConfig = NULL) const = 0;
    virtual sp<AudioPort> getAudioPort() const = 0;
    virtual bool hasSameHwModuleAs(const sp<AudioPortConfig>& other) const {
        return (other != 0) && (other->getAudioPort() != 0) && (getAudioPort() != 0) &&
                (other->getAudioPort()->getModuleHandle() == getAudioPort()->getModuleHandle());
    }
    bool hasGainController(bool canUseForVolume = false) const;

    unsigned int getSamplingRate() const { return mSamplingRate; }
    audio_format_t getFormat() const { return mFormat; }
    audio_channel_mask_t getChannelMask() const { return mChannelMask; }

protected:
    unsigned int mSamplingRate = 0u;
    audio_format_t mFormat = AUDIO_FORMAT_INVALID;
    audio_channel_mask_t mChannelMask = AUDIO_CHANNEL_NONE;
    struct audio_gain_config mGain = { .index = -1 };
    union audio_io_flags mFlags = { AUDIO_INPUT_FLAG_NONE };
};

} // namespace android
#endif
+1 −1
Original line number Diff line number Diff line
@@ -31,7 +31,7 @@ class AudioRoute;
class AudioPortVector : public Vector<sp<AudioPort> >
{
public:
    sp<AudioPort> findByTagName(const String8 &tagName) const;
    sp<AudioPort> findByTagName(const std::string &tagName) const;
};


+2 −2
Original line number Diff line number Diff line
@@ -133,14 +133,14 @@ public:
        mDefaultOutputDevice->attach(module);
        defaultInputDevice->attach(module);

        sp<OutputProfile> outProfile = new OutputProfile(String8("primary"));
        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(String8("primary"));
        sp<InputProfile> inProfile = new InputProfile("primary");
        inProfile->addAudioProfile(micProfile);
        inProfile->addSupportedDevice(defaultInputDevice);
        module->addInputProfile(inProfile);
Loading