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

Commit 112b0af8 authored by François Gaffie's avatar François Gaffie Committed by Eric Laurent
Browse files

audio policy: introduction of AudioProfile



In order to be able to declare the possible sample
specifications for an Audio Port (a given format, a list of
sample rates, a list of channels), a new object AudioProfile is
introduced.

Change-Id: Ie3ca3400f05984e7b4132fc7ba90020eb4d998c7
Signed-off-by: default avatarFrançois Gaffie <francois.gaffie@intel.com>
parent 599c758b
Loading
Loading
Loading
Loading
+0 −2
Original line number Original line Diff line number Diff line
@@ -18,9 +18,7 @@


#include <system/audio.h>
#include <system/audio.h>


static const uint32_t gDynamicRate = 0;
static const audio_format_t gDynamicFormat = AUDIO_FORMAT_DEFAULT;
static const audio_format_t gDynamicFormat = AUDIO_FORMAT_DEFAULT;
static const audio_channel_mask_t gDynamicChannelMask = AUDIO_CHANNEL_NONE;


// For mixed output and inputs, the policy will use max mixer sampling rates.
// For mixed output and inputs, the policy will use max mixer sampling rates.
// Do not limit sampling rate otherwise
// Do not limit sampling rate otherwise
+1 −0
Original line number Original line Diff line number Diff line
@@ -9,6 +9,7 @@ LOCAL_SRC_FILES:= \
    src/HwModule.cpp \
    src/HwModule.cpp \
    src/IOProfile.cpp \
    src/IOProfile.cpp \
    src/AudioPort.cpp \
    src/AudioPort.cpp \
    src/AudioProfile.cpp \
    src/AudioPolicyMix.cpp \
    src/AudioPolicyMix.cpp \
    src/AudioPatch.cpp \
    src/AudioPatch.cpp \
    src/AudioInputDescriptor.cpp \
    src/AudioInputDescriptor.cpp \
+4 −6
Original line number Original line Diff line number Diff line
@@ -99,9 +99,8 @@ public:
        sp<OutputProfile> outProfile;
        sp<OutputProfile> outProfile;
        outProfile = new OutputProfile(String8("primary"));
        outProfile = new OutputProfile(String8("primary"));
        outProfile->attach(module);
        outProfile->attach(module);
        outProfile->mSamplingRates.add(44100);
        outProfile->addAudioProfile(
        outProfile->mFormats.add(AUDIO_FORMAT_PCM_16_BIT);
                new AudioProfile(AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO, 44100));
        outProfile->mChannelMasks.add(AUDIO_CHANNEL_OUT_STEREO);
        outProfile->addSupportedDevice(mDefaultOutputDevices);
        outProfile->addSupportedDevice(mDefaultOutputDevices);
        outProfile->setFlags(AUDIO_OUTPUT_FLAG_PRIMARY);
        outProfile->setFlags(AUDIO_OUTPUT_FLAG_PRIMARY);
        module->mOutputProfiles.add(outProfile);
        module->mOutputProfiles.add(outProfile);
@@ -109,9 +108,8 @@ public:
        sp<InputProfile> inProfile;
        sp<InputProfile> inProfile;
        inProfile = new InputProfile(String8("primary"));
        inProfile = new InputProfile(String8("primary"));
        inProfile->attach(module);
        inProfile->attach(module);
        inProfile->mSamplingRates.add(8000);
        inProfile->addAudioProfile(
        inProfile->mFormats.add(AUDIO_FORMAT_PCM_16_BIT);
                new AudioProfile(AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_MONO, 8000));
        inProfile->mChannelMasks.add(AUDIO_CHANNEL_IN_MONO);
        inProfile->addSupportedDevice(defaultInputDevice);
        inProfile->addSupportedDevice(defaultInputDevice);
        module->mInputProfiles.add(inProfile);
        module->mInputProfiles.add(inProfile);


+42 −35
Original line number Original line Diff line number Diff line
@@ -16,6 +16,7 @@


#pragma once
#pragma once


#include "AudioProfile.h"
#include <utils/String8.h>
#include <utils/String8.h>
#include <utils/Vector.h>
#include <utils/Vector.h>
#include <utils/RefBase.h>
#include <utils/RefBase.h>
@@ -57,42 +58,44 @@ public:
    virtual void toAudioPort(struct audio_port *port) const;
    virtual void toAudioPort(struct audio_port *port) const;


    virtual void importAudioPort(const sp<AudioPort> port);
    virtual void importAudioPort(const sp<AudioPort> port);
    void clearCapabilities();
    void clearCapabilities() { mProfiles.clearProfiles(); }


    void setSupportedFormats(const Vector <audio_format_t> &formats);
    void addAudioProfile(const sp<AudioProfile> &profile) { mProfiles.add(profile); }
    void setSupportedSamplingRates(const Vector <uint32_t> &sampleRates)

    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
    status_t checkExactAudioProfile(uint32_t samplingRate,
                                    audio_channel_mask_t channelMask,
                                    audio_format_t format) const
    {
    {
        mSamplingRates = sampleRates;
        return mProfiles.checkExactProfile(samplingRate, channelMask, format);
    }
    }
    void setSupportedChannelMasks(const Vector <audio_channel_mask_t> &channelMasks)

    // 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
    {
    {
        mChannelMasks = channelMasks;
        return mProfiles.checkCompatibleProfile(samplingRate, channelMask, format, mType, mRole);
    }
    }


    // searches for an exact match
    void clearAudioProfiles() { return mProfiles.clearProfiles(); }
    status_t checkExactSamplingRate(uint32_t samplingRate) const;

    // searches for a compatible match, and returns the best match via updatedSamplingRate
    status_t checkCompatibleSamplingRate(uint32_t samplingRate,
            uint32_t *updatedSamplingRate) const;
    // searches for an exact match
    status_t checkExactChannelMask(audio_channel_mask_t channelMask) const;
    // searches for a compatible match, currently implemented for input channel masks only
    status_t checkCompatibleChannelMask(audio_channel_mask_t channelMask,
            audio_channel_mask_t *updatedChannelMask) const;

    status_t checkExactFormat(audio_format_t format) const;
    // searches for a compatible match, currently implemented for input formats only
    status_t checkCompatibleFormat(audio_format_t format, audio_format_t *updatedFormat) const;
    status_t checkGain(const struct audio_gain_config *gainConfig, int index) const;
    status_t checkGain(const struct audio_gain_config *gainConfig, int index) const;


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


    static const audio_format_t sPcmFormatCompareTable[];
    static const audio_format_t sPcmFormatCompareTable[];
    static int compareFormats(const audio_format_t *format1, const audio_format_t *format2) {

        return compareFormats(*format1, *format2);
    }
    static int compareFormats(audio_format_t format1, audio_format_t format2);
    static int compareFormats(audio_format_t format1, audio_format_t format2);


    audio_module_handle_t getModuleHandle() const;
    audio_module_handle_t getModuleHandle() const;
@@ -105,23 +108,27 @@ public:
                ((mType == AUDIO_PORT_TYPE_MIX) && (mRole == AUDIO_PORT_ROLE_SINK));
                ((mType == AUDIO_PORT_TYPE_MIX) && (mRole == AUDIO_PORT_ROLE_SINK));
    }
    }


    void dump(int fd, int spaces) const;
    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(int fd, int spaces, bool verbose = true) const;
    void log(const char* indent) const;
    void log(const char* indent) const;


    // by convention, "0' in the first entry in mSamplingRates, mChannelMasks or mFormats
    // indicates the supported parameters should be read from the output stream
    // after it is opened for the first time
    Vector <uint32_t> mSamplingRates; // supported sampling rates
    Vector <audio_channel_mask_t> mChannelMasks; // supported channel masks
    Vector <audio_format_t> mFormats; // supported audio formats
    AudioGainCollection mGains; // gain controllers
    AudioGainCollection mGains; // gain controllers
    sp<HwModule> mModule;                 // audio HW module exposing this I/O stream
    sp<HwModule> mModule;                 // audio HW module exposing this I/O stream


private:
private:
    void pickChannelMask(audio_channel_mask_t &channelMask, const ChannelsVector &channelMasks) const;
    void pickSamplingRate(uint32_t &rate,const SampleRateVector &samplingRates) const;

    String8           mName;
    String8           mName;
    audio_port_type_t mType;
    audio_port_type_t mType;
    audio_port_role_t mRole;
    audio_port_role_t mRole;
    uint32_t mFlags; // attribute flags mask (e.g primary output, direct output...).
    uint32_t mFlags; // attribute flags mask (e.g primary output, direct output...).
    AudioProfileVector mProfiles; // AudioProfiles supported by this port (format, Rates, Channels)
    static volatile int32_t mNextUniqueId;
    static volatile int32_t mNextUniqueId;
};
};


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

#pragma once

#include "policy.h"
#include <utils/String8.h>
#include <utils/SortedVector.h>
#include <utils/RefBase.h>
#include <utils/Errors.h>
#include <system/audio.h>
#include <cutils/config_utils.h>

namespace android {

typedef SortedVector<uint32_t> SampleRateVector;
typedef SortedVector<audio_channel_mask_t> ChannelsVector;
typedef Vector<audio_format_t> FormatVector;

template <typename T>
bool operator == (const SortedVector<T> &left, const SortedVector<T> &right);

class AudioProfile : public virtual RefBase
{
public:
    AudioProfile(audio_format_t format,
                 audio_channel_mask_t channelMasks,
                 uint32_t samplingRate) :
        mName(String8("")),
        mFormat(format)
    {
        mChannelMasks.add(channelMasks);
        mSamplingRates.add(samplingRate);
    }

    AudioProfile(audio_format_t format,
                 const ChannelsVector &channelMasks,
                 const SampleRateVector &samplingRateCollection) :
        mName(String8("")),
        mFormat(format),
        mChannelMasks(channelMasks),
        mSamplingRates(samplingRateCollection)
    {}

    audio_format_t getFormat() const { return mFormat; }

    void setChannels(const ChannelsVector &channelMasks)
    {
        if (mIsDynamicChannels) {
            mChannelMasks = channelMasks;
        }
    }
    const ChannelsVector &getChannels() const { return mChannelMasks; }

    void setSampleRates(const SampleRateVector &sampleRates)
    {
        if (mIsDynamicRate) {
            mSamplingRates = sampleRates;
        }
    }
    const SampleRateVector &getSampleRates() const { return mSamplingRates; }

    bool isValid() const { return hasValidFormat() && hasValidRates() && hasValidChannels(); }

    void clear()
    {
        if (mIsDynamicChannels) {
            mChannelMasks.clear();
        }
        if (mIsDynamicRate) {
            mSamplingRates.clear();
        }
    }

    inline bool supportsChannels(audio_channel_mask_t channels) const
    {
        return mChannelMasks.indexOf(channels) >= 0;
    }
    inline bool supportsRate(uint32_t rate) const
    {
        return mSamplingRates.indexOf(rate) >= 0;
    }

    status_t checkExact(uint32_t rate, audio_channel_mask_t channels, audio_format_t format) const;

    status_t checkCompatibleChannelMask(audio_channel_mask_t channelMask,
                                        audio_channel_mask_t &updatedChannelMask,
                                        audio_port_type_t portType,
                                        audio_port_role_t portRole) const;

    status_t checkCompatibleSamplingRate(uint32_t samplingRate,
                                         uint32_t &updatedSamplingRate) const;

    bool hasValidFormat() const { return mFormat != AUDIO_FORMAT_DEFAULT; }
    bool hasValidRates() const { return !mSamplingRates.isEmpty(); }
    bool hasValidChannels() const { return !mChannelMasks.isEmpty(); }

    void setDynamicChannels(bool dynamic) { mIsDynamicChannels = dynamic; }
    bool isDynamicChannels() const { return mIsDynamicChannels; }

    void setDynamicRate(bool dynamic) { mIsDynamicRate = dynamic; }
    bool isDynamicRate() const { return mIsDynamicRate; }

    void setDynamicFormat(bool dynamic) { mIsDynamicFormat = dynamic; }
    bool isDynamicFormat() const { return mIsDynamicFormat; }

    bool isDynamic() { return mIsDynamicFormat || mIsDynamicChannels || mIsDynamicRate; }

    void dump(int fd, int spaces) const;

private:
    String8  mName;
    audio_format_t mFormat;
    ChannelsVector mChannelMasks;
    SampleRateVector mSamplingRates;

    bool mIsDynamicFormat = false;
    bool mIsDynamicChannels = false;
    bool mIsDynamicRate = false;
};


class AudioProfileVector : public Vector<sp<AudioProfile> >
{
public:
    ssize_t add(const sp<AudioProfile> &profile)
    {
        ssize_t index = Vector::add(profile);
        // we sort from worst to best, so that AUDIO_FORMAT_DEFAULT is always the first entry.
        // TODO: compareFormats could be a lambda to convert between pointer-to-format to format:
        // [](const audio_format_t *format1, const audio_format_t *format2) {
        //     return compareFormats(*format1, *format2);
        // }
        sort(compareFormats);
        return index;
    }

    // This API is intended to be used by the policy manager once retrieving capabilities
    // for a profile with dynamic format, rate and channels attributes
    ssize_t addProfileFromHal(const sp<AudioProfile> &profileToAdd)
    {
        // Check valid profile to add:
        if (!profileToAdd->hasValidFormat()) {
            return -1;
        }
        if (!profileToAdd->hasValidChannels() && !profileToAdd->hasValidRates()) {
            FormatVector formats;
            formats.add(profileToAdd->getFormat());
            setFormats(FormatVector(formats));
            return 0;
        }
        if (!profileToAdd->hasValidChannels() && profileToAdd->hasValidRates()) {
            setSampleRatesFor(profileToAdd->getSampleRates(), profileToAdd->getFormat());
            return 0;
        }
        if (profileToAdd->hasValidChannels() && !profileToAdd->hasValidRates()) {
            setChannelsFor(profileToAdd->getChannels(), profileToAdd->getFormat());
            return 0;
        }
        // Go through the list of profile to avoid duplicates
        for (size_t profileIndex = 0; profileIndex < size(); profileIndex++) {
            const sp<AudioProfile> &profile = itemAt(profileIndex);
            if (profile->isValid() && profile == profileToAdd) {
                // Nothing to do
                return profileIndex;
            }
        }
        profileToAdd->setDynamicFormat(true); // set the format as dynamic to allow removal
        return add(profileToAdd);
    }

    sp<AudioProfile> getFirstValidProfile() const
    {
        for (size_t i = 0; i < size(); i++) {
            if (itemAt(i)->isValid()) {
                return itemAt(i);
            }
        }
        return 0;
    }

    bool hasValidProfile() const { return getFirstValidProfile() != 0; }

    status_t checkExactProfile(uint32_t samplingRate, audio_channel_mask_t channelMask,
                               audio_format_t format) const;

    status_t checkCompatibleProfile(uint32_t &samplingRate, audio_channel_mask_t &channelMask,
                                    audio_format_t &format,
                                    audio_port_type_t portType,
                                    audio_port_role_t portRole) const;

    FormatVector getSupportedFormats() const
    {
        FormatVector supportedFormats;
        for (size_t i = 0; i < size(); i++) {
            if (itemAt(i)->hasValidFormat()) {
                supportedFormats.add(itemAt(i)->getFormat());
            }
        }
        return supportedFormats;
    }

    bool hasDynamicProfile() const
    {
        for (size_t i = 0; i < size(); i++) {
            if (itemAt(i)->isDynamic()) {
                return true;
            }
        }
        return false;
    }

    bool hasDynamicFormat() const
    {
        return getProfileFor(gDynamicFormat) != 0;
    }

    bool hasDynamicChannelsFor(audio_format_t format) const
    {
       for (size_t i = 0; i < size(); i++) {
           sp<AudioProfile> profile = itemAt(i);
           if (profile->getFormat() == format && profile->isDynamicChannels()) {
               return true;
           }
       }
       return false;
    }

    bool hasDynamicRateFor(audio_format_t format) const
    {
        for (size_t i = 0; i < size(); i++) {
            sp<AudioProfile> profile = itemAt(i);
            if (profile->getFormat() == format && profile->isDynamicRate()) {
                return true;
            }
        }
        return false;
    }

    // One audio profile will be added for each format supported by Audio HAL
    void setFormats(const FormatVector &formats)
    {
        // Only allow to change the format of dynamic profile
        sp<AudioProfile> dynamicFormatProfile = getProfileFor(gDynamicFormat);
        if (dynamicFormatProfile == 0) {
            return;
        }
        clearProfiles();
        for (size_t i = 0; i < formats.size(); i++) {
            sp<AudioProfile> profile = new AudioProfile(formats[i],
                                                        dynamicFormatProfile->getChannels(),
                                                        dynamicFormatProfile->getSampleRates());
            profile->setDynamicFormat(true);
            profile->setDynamicChannels(dynamicFormatProfile->isDynamicChannels());
            profile->setDynamicRate(dynamicFormatProfile->isDynamicRate());
            add(profile);
        }
    }

    void setSampleRatesFor(const SampleRateVector &sampleRates, audio_format_t format)
    {
        for (size_t i = 0; i < size(); i++) {
            sp<AudioProfile> profile = itemAt(i);
            if (profile->getFormat() == format && profile->isDynamicRate()) {
                if (profile->hasValidRates()) {
                    // Need to create a new profile with same format
                    sp<AudioProfile> profileToAdd = new AudioProfile(format, profile->getChannels(),
                                                                     sampleRates);
                    profileToAdd->setDynamicFormat(true); // need to set to allow cleaning
                    add(profileToAdd);
                } else {
                    profile->setSampleRates(sampleRates);
                }
                return;
            }
        }
    }

    void setChannelsFor(const ChannelsVector &channelMasks, audio_format_t format)
    {
        for (size_t i = 0; i < size(); i++) {
            sp<AudioProfile> profile = itemAt(i);
            if (profile->getFormat() == format && profile->isDynamicChannels()) {
                if (profile->hasValidChannels()) {
                    // Need to create a new profile with same format
                    sp<AudioProfile> profileToAdd = new AudioProfile(format, channelMasks,
                                                                     profile->getSampleRates());
                    profileToAdd->setDynamicFormat(true); // need to set to allow cleaning
                    add(profileToAdd);
                } else {
                    profile->setChannels(channelMasks);
                }
                return;
            }
        }
    }

    void clearProfiles()
    {
        for (size_t i = size(); i != 0; ) {
            sp<AudioProfile> profile = itemAt(--i);
            if (profile->isDynamicFormat() && profile->hasValidFormat()) {
                removeAt(i);
                continue;
            }
            profile->clear();
        }
    }

    void dump(int fd, int spaces) const
    {
        const size_t SIZE = 256;
        char buffer[SIZE];

        snprintf(buffer, SIZE, "%*s- Profiles:\n", spaces, "");
        write(fd, buffer, strlen(buffer));
        for (size_t i = 0; i < size(); i++) {
            snprintf(buffer, SIZE, "%*sProfile %zu:", spaces + 4, "", i);
            write(fd, buffer, strlen(buffer));
            itemAt(i)->dump(fd, spaces + 8);
        }
    }

private:
    sp<AudioProfile> getProfileFor(audio_format_t format) const
    {
        for (size_t i = 0; i < size(); i++) {
            if (itemAt(i)->getFormat() == format) {
                return itemAt(i);
            }
        }
        return 0;
    }

    static int compareFormats(const sp<AudioProfile> *profile1, const sp<AudioProfile> *profile2);
};

bool operator == (const AudioProfile &left, const AudioProfile &right);

}; // namespace android
Loading