Merge changes I05611b70,I6cd1a53e,Ic2e08efc,I13ac0673,I0d87fd76 am: 1e415c058a

am: 7cde662ae3

Change-Id: I00be2cf94686e70ec45038c05767188f96659308
gugelfrei
jiabin 5 years ago committed by android-build-merger
commit f1e48f349f

@ -10,17 +10,21 @@ cc_library_shared {
srcs: [
"AudioGain.cpp",
"AudioPortBase.cpp",
"AudioProfile.cpp",
],
shared_libs: [
"libbase",
"libbinder",
"liblog",
"libmedia_helper",
"libutils",
],
header_libs: [
"libaudio_system_headers",
"libaudioclient_headers",
"libaudiofoundation_headers",
],

@ -0,0 +1,87 @@
/*
* 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);
}
}
}
}
}

@ -0,0 +1,222 @@
/*
* 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.
*/
#include <set>
#define LOG_TAG "AudioProfile"
//#define LOG_NDEBUG 0
#include <android-base/stringprintf.h>
#include <media/AudioContainers.h>
#include <media/AudioProfile.h>
#include <media/TypeConverter.h>
#include <utils/Errors.h>
namespace android {
bool operator == (const AudioProfile &left, const AudioProfile &right)
{
return (left.getFormat() == right.getFormat()) &&
(left.getChannels() == right.getChannels()) &&
(left.getSampleRates() == right.getSampleRates());
}
// static
sp<AudioProfile> AudioProfile::createFullDynamic(audio_format_t dynamicFormat)
{
AudioProfile* dynamicProfile = new AudioProfile(dynamicFormat,
ChannelMaskSet(), SampleRateSet());
dynamicProfile->setDynamicFormat(true);
dynamicProfile->setDynamicChannels(true);
dynamicProfile->setDynamicRate(true);
return dynamicProfile;
}
AudioProfile::AudioProfile(audio_format_t format,
audio_channel_mask_t channelMasks,
uint32_t samplingRate) :
mName(""),
mFormat(format)
{
mChannelMasks.insert(channelMasks);
mSamplingRates.insert(samplingRate);
}
AudioProfile::AudioProfile(audio_format_t format,
const ChannelMaskSet &channelMasks,
const SampleRateSet &samplingRateCollection) :
mName(""),
mFormat(format),
mChannelMasks(channelMasks),
mSamplingRates(samplingRateCollection) {}
void AudioProfile::setChannels(const ChannelMaskSet &channelMasks)
{
if (mIsDynamicChannels) {
mChannelMasks = channelMasks;
}
}
void AudioProfile::setSampleRates(const SampleRateSet &sampleRates)
{
if (mIsDynamicRate) {
mSamplingRates = sampleRates;
}
}
void AudioProfile::clear()
{
if (mIsDynamicChannels) {
mChannelMasks.clear();
}
if (mIsDynamicRate) {
mSamplingRates.clear();
}
}
void AudioProfile::dump(std::string *dst, int spaces) const
{
dst->append(base::StringPrintf("%s%s%s\n", mIsDynamicFormat ? "[dynamic format]" : "",
mIsDynamicChannels ? "[dynamic channels]" : "",
mIsDynamicRate ? "[dynamic rates]" : ""));
if (mName.length() != 0) {
dst->append(base::StringPrintf("%*s- name: %s\n", spaces, "", mName.c_str()));
}
std::string formatLiteral;
if (FormatConverter::toString(mFormat, formatLiteral)) {
dst->append(base::StringPrintf("%*s- format: %s\n", spaces, "", formatLiteral.c_str()));
}
if (!mSamplingRates.empty()) {
dst->append(base::StringPrintf("%*s- sampling rates:", spaces, ""));
for (auto it = mSamplingRates.begin(); it != mSamplingRates.end();) {
dst->append(base::StringPrintf("%d", *it));
dst->append(++it == mSamplingRates.end() ? "" : ", ");
}
dst->append("\n");
}
if (!mChannelMasks.empty()) {
dst->append(base::StringPrintf("%*s- channel masks:", spaces, ""));
for (auto it = mChannelMasks.begin(); it != mChannelMasks.end();) {
dst->append(base::StringPrintf("0x%04x", *it));
dst->append(++it == mChannelMasks.end() ? "" : ", ");
}
dst->append("\n");
}
}
ssize_t AudioProfileVectorBase::add(const sp<AudioProfile> &profile)
{
ssize_t index = size();
push_back(profile);
return index;
}
void AudioProfileVectorBase::clearProfiles()
{
for (auto it = begin(); it != end();) {
if ((*it)->isDynamicFormat() && (*it)->hasValidFormat()) {
it = erase(it);
} else {
(*it)->clear();
++it;
}
}
}
sp<AudioProfile> AudioProfileVectorBase::getFirstValidProfile() const
{
for (const auto &profile : *this) {
if (profile->isValid()) {
return profile;
}
}
return nullptr;
}
sp<AudioProfile> AudioProfileVectorBase::getFirstValidProfileFor(audio_format_t format) const
{
for (const auto &profile : *this) {
if (profile->isValid() && profile->getFormat() == format) {
return profile;
}
}
return nullptr;
}
FormatVector AudioProfileVectorBase::getSupportedFormats() const
{
FormatVector supportedFormats;
for (const auto &profile : *this) {
if (profile->hasValidFormat()) {
supportedFormats.push_back(profile->getFormat());
}
}
return supportedFormats;
}
bool AudioProfileVectorBase::hasDynamicChannelsFor(audio_format_t format) const
{
for (const auto &profile : *this) {
if (profile->getFormat() == format && profile->isDynamicChannels()) {
return true;
}
}
return false;
}
bool AudioProfileVectorBase::hasDynamicFormat() const
{
for (const auto &profile : *this) {
if (profile->isDynamicFormat()) {
return true;
}
}
return false;
}
bool AudioProfileVectorBase::hasDynamicProfile() const
{
for (const auto &profile : *this) {
if (profile->isDynamic()) {
return true;
}
}
return false;
}
bool AudioProfileVectorBase::hasDynamicRateFor(audio_format_t format) const
{
for (const auto &profile : *this) {
if (profile->getFormat() == format && profile->isDynamicRate()) {
return true;
}
}
return false;
}
void AudioProfileVectorBase::dump(std::string *dst, int spaces) const
{
dst->append(base::StringPrintf("%*s- Profiles:\n", spaces, ""));
for (size_t i = 0; i < size(); i++) {
dst->append(base::StringPrintf("%*sProfile %zu:", spaces + 4, "", i));
std::string profileStr;
at(i)->dump(&profileStr, spaces + 8);
dst->append(profileStr);
}
}
} // namespace android

@ -0,0 +1,130 @@
/*
* 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.
*/
#pragma once
#include <string>
#include <media/AudioGain.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 AudioPortFoundation : public virtual RefBase
{
public:
AudioPortFoundation(const std::string& name, audio_port_type_t type, audio_port_role_t role) :
mName(name), mType(type), mRole(role) {}
virtual ~AudioPortFoundation() = default;
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 std::string getTagName() const = 0;
void setGains(const AudioGains &gains) { mGains = gains; }
const AudioGains &getGains() const { return mGains; }
virtual void toAudioPort(struct audio_port *port) const;
virtual AudioProfileVectorBase* getAudioProfileVectorBase() const = 0;
virtual void addAudioProfile(const sp<AudioProfile> &profile) {
getAudioProfileVectorBase()->add(profile);
}
virtual void clearAudioProfiles() {
getAudioProfileVectorBase()->clearProfiles();
}
bool hasValidAudioProfile() const { return getAudioProfileVectorBase()->hasValidProfile(); }
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
{
return ((mType == AUDIO_PORT_TYPE_DEVICE) && (mRole == AUDIO_PORT_ROLE_SOURCE)) ||
((mType == AUDIO_PORT_TYPE_MIX) && (mRole == AUDIO_PORT_ROLE_SINK));
}
void dump(std::string *dst, int spaces, bool verbose = true) const;
AudioGains mGains; // gain controllers
protected:
std::string mName;
audio_port_type_t mType;
audio_port_role_t mRole;
};
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) {}
virtual ~AudioPortBase() {}
AudioProfileVectorBase* getAudioProfileVectorBase() const override {
return static_cast<AudioProfileVectorBase*>(const_cast<ProfileVector*>(&mProfiles));
}
void addAudioProfile(const sp<AudioProfile> &profile) override { mProfiles.add(profile); }
void clearAudioProfiles() override { return mProfiles.clearProfiles(); }
void setAudioProfiles(const ProfileVector &profiles) { mProfiles = profiles; }
ProfileVector &getAudioProfiles() { return mProfiles; }
protected:
ProfileVector mProfiles; // AudioProfiles supported by this port (format, Rates, Channels)
};
class AudioPortConfigBase : public virtual RefBase
{
public:
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;
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 };
};
} // namespace android

@ -16,19 +16,19 @@
#pragma once
#include <string>
#include <vector>
#include <media/AudioContainers.h>
#include <system/audio.h>
#include <utils/RefBase.h>
#include <utils/String8.h>
#include "policy.h"
namespace android {
class AudioProfile : public virtual RefBase
class AudioProfile final : public RefBase
{
public:
static sp<AudioProfile> createFullDynamic();
static sp<AudioProfile> createFullDynamic(audio_format_t dynamicFormat = AUDIO_FORMAT_DEFAULT);
AudioProfile(audio_format_t format, audio_channel_mask_t channelMasks, uint32_t samplingRate);
AudioProfile(audio_format_t format,
@ -49,14 +49,6 @@ public:
}
bool supportsRate(uint32_t rate) const { return mSamplingRates.count(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.empty(); }
bool hasValidChannels() const { return !mChannelMasks.empty(); }
@ -72,11 +64,11 @@ public:
bool isDynamic() { return mIsDynamicFormat || mIsDynamicChannels || mIsDynamicRate; }
void dump(String8 *dst, int spaces) const;
void dump(std::string *dst, int spaces) const;
private:
String8 mName;
audio_format_t mFormat;
std::string mName;
audio_format_t mFormat; // The format for an audio profile should only be set when initialized.
ChannelMaskSet mChannelMasks;
SampleRateSet mSamplingRates;
@ -85,35 +77,16 @@ private:
bool mIsDynamicRate = false;
};
class AudioProfileVector : public std::vector<sp<AudioProfile> >
class AudioProfileVectorBase : public std::vector<sp<AudioProfile> >
{
public:
ssize_t add(const sp<AudioProfile> &profile);
// 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);
void appendProfiles(const AudioProfileVector& audioProfiles) {
insert(end(), audioProfiles.begin(), audioProfiles.end());
}
virtual ~AudioProfileVectorBase() = default;
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;
void clearProfiles();
// Assuming that this profile vector contains input profiles,
// find the best matching config from 'outputProfiles', according to
// the given preferences for audio formats and channel masks.
// Note: std::vectors are used because specialized containers for formats
// and channels can be sorted and use their own ordering.
status_t findBestMatchingOutputConfig(const AudioProfileVector& outputProfiles,
const std::vector<audio_format_t>& preferredFormats, // order: most pref -> least pref
const std::vector<audio_channel_mask_t>& preferredOutputChannels,
bool preferHigherSamplingRates,
audio_config_base *bestOutputConfig) const;
virtual ssize_t add(const sp<AudioProfile> &profile);
// If the profile is dynamic format and has valid format, it will be removed when doing
// clearProfiles(). Otherwise, AudioProfile::clear() will be called.
virtual void clearProfiles();
sp<AudioProfile> getFirstValidProfile() const;
sp<AudioProfile> getFirstValidProfileFor(audio_format_t format) const;
@ -121,19 +94,11 @@ public:
FormatVector getSupportedFormats() const;
bool hasDynamicChannelsFor(audio_format_t format) const;
bool hasDynamicFormat() const { return getProfileFor(gDynamicFormat) != 0; }
bool hasDynamicFormat() const;
bool hasDynamicProfile() const;
bool hasDynamicRateFor(audio_format_t format) const;
// One audio profile will be added for each format supported by Audio HAL
void setFormats(const FormatVector &formats);
void dump(String8 *dst, int spaces) const;
private:
sp<AudioProfile> getProfileFor(audio_format_t format) const;
void setSampleRatesFor(const SampleRateSet &sampleRates, audio_format_t format);
void setChannelsFor(const ChannelMaskSet &channelMasks, audio_format_t format);
virtual void dump(std::string *dst, int spaces) const;
};
bool operator == (const AudioProfile &left, const AudioProfile &right);

@ -8,7 +8,7 @@ cc_library_static {
"src/AudioPatch.cpp",
"src/AudioPolicyMix.cpp",
"src/AudioPort.cpp",
"src/AudioProfile.cpp",
"src/AudioProfileVector.cpp",
"src/AudioRoute.cpp",
"src/ClientDescriptor.cpp",
"src/DeviceDescriptor.cpp",

@ -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;
};

@ -29,6 +29,7 @@
#include <AudioPolicyMix.h>
#include <EffectDescriptor.h>
#include <SoundTriggerSession.h>
#include <media/AudioProfile.h>
namespace android {
@ -118,9 +119,9 @@ public:
mSource = "AudioPolicyConfig::setDefault";
mEngineLibraryNameSuffix = kDefaultEngineLibraryNameSuffix;
mDefaultOutputDevice = new DeviceDescriptor(AUDIO_DEVICE_OUT_SPEAKER);
mDefaultOutputDevice->addAudioProfile(AudioProfile::createFullDynamic());
mDefaultOutputDevice->addAudioProfile(AudioProfile::createFullDynamic(gDynamicFormat));
sp<DeviceDescriptor> defaultInputDevice = new DeviceDescriptor(AUDIO_DEVICE_IN_BUILTIN_MIC);
defaultInputDevice->addAudioProfile(AudioProfile::createFullDynamic());
defaultInputDevice->addAudioProfile(AudioProfile::createFullDynamic(gDynamicFormat));
sp<AudioProfile> micProfile = new AudioProfile(
AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_MONO, 8000);
defaultInputDevice->addAudioProfile(micProfile);
@ -132,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);

@ -17,9 +17,10 @@
#pragma once
#include "AudioCollections.h"
#include "AudioProfile.h"
#include "AudioProfileVector.h"
#include "HandleGenerator.h"
#include <media/AudioGain.h>
#include <media/AudioPortBase.h>
#include <utils/String8.h>
#include <utils/Vector.h>
#include <utils/RefBase.h>
@ -32,25 +33,15 @@ namespace android {
class HwModule;
class AudioRoute;
class AudioPort : public virtual RefBase, private HandleGenerator<audio_port_handle_t>
class AudioPort : public virtual RefBase, public AudioPortBase<AudioProfileVector>,
private HandleGenerator<audio_port_handle_t>
{
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) {}
AudioPort(const std::string& name, audio_port_type_t type, audio_port_role_t role) :
AudioPortBase(name, type, role), mFlags(AUDIO_OUTPUT_FLAG_NONE) {}
virtual ~AudioPort() {}
void setName(const String8 &name) { mName = name; }
const String8 &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;
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
@ -70,18 +61,9 @@ public:
// 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(); }
bool hasDynamicAudioProfile() const { return getAudioProfileVectorBase()->hasDynamicProfile(); }
// searches for an exact match
virtual status_t checkExactAudioProfile(const struct audio_port_config *config) const;
@ -95,10 +77,6 @@ public:
return mProfiles.checkCompatibleProfile(samplingRate, channelMask, format, mType, mRole);
}
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;
@ -121,12 +99,6 @@ public:
const char *getModuleName() const;
sp<HwModule> getModule() const { return mModule; }
bool useInputChannelMask() const
{
return ((mType == AUDIO_PORT_TYPE_DEVICE) && (mRole == AUDIO_PORT_ROLE_SOURCE)) ||
((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) &&
@ -136,44 +108,36 @@ public:
void addRoute(const sp<AudioRoute> &route) { mRoutes.add(route); }
const AudioRouteVector &getRoutes() const { return mRoutes; }
void dump(String8 *dst, int spaces, bool verbose = true) const;
void log(const char* indent) const;
AudioGains mGains; // gain controllers
private:
void pickChannelMask(audio_channel_mask_t &channelMask,
const ChannelMaskSet &channelMasks) const;
void pickSamplingRate(uint32_t &rate, const SampleRateSet &samplingRates) const;
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)
sp<HwModule> mModule; // audio HW module exposing this I/O stream
AudioRouteVector mRoutes; // Routes involving this port
};
class AudioPortConfig : public virtual RefBase
class AudioPortConfig : public AudioPortConfigBase
{
public:
status_t applyAudioPortConfig(const struct audio_port_config *config,
struct audio_port_config *backupConfig = NULL);
struct audio_port_config *backupConfig = NULL) override;
virtual void toAudioPortConfig(struct audio_port_config *dstConfig,
const struct audio_port_config *srcConfig = NULL) const = 0;
const struct audio_port_config *srcConfig = NULL) const override;
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 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 };
};

@ -0,0 +1,68 @@
/*
* 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 <media/AudioProfile.h>
#include <system/audio.h>
namespace android {
class AudioProfileVector : public AudioProfileVectorBase {
public:
virtual ~AudioProfileVector() = default;
ssize_t add(const sp<AudioProfile> &profile) override;
// 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);
void appendProfiles(const AudioProfileVectorBase& audioProfiles) {
insert(end(), audioProfiles.begin(), audioProfiles.end());
}
status_t checkExactProfile(const 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;
// Assuming that this profile vector contains input profiles,
// find the best matching config from 'outputProfiles', according to
// the given preferences for audio formats and channel masks.
// Note: std::vectors are used because specialized containers for formats
// and channels can be sorted and use their own ordering.
status_t findBestMatchingOutputConfig(
const AudioProfileVector &outputProfiles,
const std::vector<audio_format_t> &preferredFormats, // order: most pref -> least pref
const std::vector<audio_channel_mask_t> &preferredOutputChannels,
bool preferHigherSamplingRates,
audio_config_base *bestOutputConfig) const;
// One audio profile will be added for each format supported by Audio HAL
void setFormats(const FormatVector &formats);
private:
sp<AudioProfile> getProfileFor(audio_format_t format) const;
void setSampleRatesFor(const SampleRateSet &sampleRates, audio_format_t format);
void setChannelsFor(const ChannelMaskSet &channelMasks, audio_format_t format);
};
} // namespace android

@ -30,13 +30,13 @@ class DeviceDescriptor : public AudioPort, public AudioPortConfig
{
public:
// Note that empty name refers by convention to a generic device.
explicit DeviceDescriptor(audio_devices_t type, const String8 &tagName = String8(""));
explicit DeviceDescriptor(audio_devices_t type, const std::string &tagName = "");
DeviceDescriptor(audio_devices_t type, const FormatVector &encodedFormats,
const String8 &tagName = String8(""));
const std::string &tagName = "");
virtual ~DeviceDescriptor() {}
virtual const String8 getTagName() const { return mTagName; }
virtual const std::string getTagName() const { return mTagName; }
audio_devices_t type() const { return mDeviceType; }
String8 address() const { return mAddress; }
@ -75,7 +75,7 @@ public:
private:
String8 mAddress{""};
String8 mTagName; // Unique human readable identifier for a device port found in conf file.
std::string mTagName; // Unique human readable identifier for a device port found in conf file.
audio_devices_t mDeviceType;
FormatVector mEncodedFormats;
audio_port_handle_t mId = AUDIO_PORT_HANDLE_NONE;
@ -112,10 +112,17 @@ public:
* equal to AUDIO_PORT_HANDLE_NONE, it also returns a nullptr.
*/
sp<DeviceDescriptor> getDeviceFromId(audio_port_handle_t id) const;
sp<DeviceDescriptor> getDeviceFromTagName(const String8 &tagName) const;
sp<DeviceDescriptor> getDeviceFromTagName(const std::string &tagName) const;
DeviceVector getDevicesFromHwModule(audio_module_handle_t moduleHandle) const;
audio_devices_t getDeviceTypesFromHwModule(audio_module_handle_t moduleHandle) const;
DeviceVector getFirstDevicesFromTypes(std::vector<audio_devices_t> orderedTypes) const;
sp<DeviceDescriptor> getFirstExistingDevice(std::vector<audio_devices_t> orderedTypes) const;
// If there are devices with the given type and the devices to add is not empty,
// remove all the devices with the given type and add all the devices to add.
void replaceDevicesByType(audio_devices_t typeToRemove, const DeviceVector &devicesToAdd);
bool contains(const sp<DeviceDescriptor>& item) const { return indexOf(item) >= 0; }
/**

@ -82,17 +82,17 @@ public:
status_t addInputProfile(const sp<IOProfile> &profile);
status_t addProfile(const sp<IOProfile> &profile);
status_t addOutputProfile(const String8& name, const audio_config_t *config,
status_t addOutputProfile(const std::string& name, const audio_config_t *config,
audio_devices_t device, const String8& address);
status_t removeOutputProfile(const String8& name);
status_t addInputProfile(const String8& name, const audio_config_t *config,
status_t removeOutputProfile(const std::string& name);
status_t addInputProfile(const std::string& name, const audio_config_t *config,
audio_devices_t device, const String8& address);
status_t removeInputProfile(const String8& name);
status_t removeInputProfile(const std::string& name);
audio_module_handle_t getHandle() const { return mHandle; }
void setHandle(audio_module_handle_t handle);
sp<AudioPort> findPortByTagName(const String8 &tagName) const
sp<AudioPort> findPortByTagName(const std::string &tagName) const
{
return mPorts.findByTagName(tagName);
}

@ -18,6 +18,7 @@
#include "AudioPort.h"
#include "DeviceDescriptor.h"
#include "policy.h"
#include <utils/String8.h>
#include <system/audio.h>
@ -33,7 +34,7 @@ class HwModule;
class IOProfile : public AudioPort
{
public:
IOProfile(const String8 &name, audio_port_role_t role)
IOProfile(const std::string &name, audio_port_role_t role)
: AudioPort(name, AUDIO_PORT_TYPE_MIX, role),
maxOpenCount(1),
curOpenCount(0),
@ -41,7 +42,7 @@ public:
curActiveCount(0) {}
// For a Profile aka MixPort, tag name and name are equivalent.
virtual const String8 getTagName() const { return getName(); }
virtual const std::string getTagName() const { return getName(); }
// FIXME: this is needed because shared MMAP stream clients use the same audio session.
// Once capture clients are tracked individually and not per session this can be removed
@ -183,13 +184,13 @@ private:
class InputProfile : public IOProfile
{
public:
explicit InputProfile(const String8 &name) : IOProfile(name, AUDIO_PORT_ROLE_SINK) {}
explicit InputProfile(const std::string &name) : IOProfile(name, AUDIO_PORT_ROLE_SINK) {}
};
class OutputProfile : public IOProfile
{
public:
explicit OutputProfile(const String8 &name) : IOProfile(name, AUDIO_PORT_ROLE_SOURCE) {}
explicit OutputProfile(const std::string &name) : IOProfile(name, AUDIO_PORT_ROLE_SOURCE) {}
};
} // namespace android

@ -24,7 +24,7 @@
namespace android {
sp<AudioPort> AudioPortVector::findByTagName(const String8 &tagName) const
sp<AudioPort> AudioPortVector::findByTagName(const std::string &tagName) const
{
for (const auto& port : *this) {
if (port->getTagName() == tagName) {

@ -34,8 +34,8 @@ AudioInputDescriptor::AudioInputDescriptor(const sp<IOProfile>& profile,
{
if (profile != NULL) {
profile->pickAudioProfile(mSamplingRate, mChannelMask, mFormat);
if (profile->mGains.size() > 0) {
profile->mGains[0]->getDefaultConfig(&mGain);
if (profile->getGains().size() > 0) {
profile->getGains()[0]->getDefaultConfig(&mGain);
}
}
}
@ -212,7 +212,7 @@ status_t AudioInputDescriptor::open(const audio_config_t *config,
mDevice = device;
ALOGV("opening input for device %s profile %p name %s",
mDevice->toString().c_str(), mProfile.get(), mProfile->getName().string());
mDevice->toString().c_str(), mProfile.get(), mProfile->getName().c_str());
audio_devices_t deviceType = mDevice->type();

@ -40,8 +40,8 @@ AudioOutputDescriptor::AudioOutputDescriptor(const sp<AudioPort>& port,
{
if (mPort.get() != nullptr) {
mPort->pickAudioProfile(mSamplingRate, mChannelMask, mFormat);
if (mPort->mGains.size() > 0) {
mPort->mGains[0]->getDefaultConfig(&mGain);
if (mPort->getGains().size() > 0) {
mPort->getGains()[0]->getDefaultConfig(&mGain);
}
}
}
@ -483,7 +483,7 @@ status_t SwAudioOutputDescriptor::open(const audio_config_t *config,
mFlags = (audio_output_flags_t)(mFlags | flags);
ALOGV("opening output for device %s profile %p name %s",
mDevices.toString().c_str(), mProfile.get(), mProfile->getName().string());
mDevices.toString().c_str(), mProfile.get(), mProfile->getName().c_str());
status_t status = mClientInterface->openOutput(mProfile->getModuleHandle(),
output,

@ -30,7 +30,7 @@ namespace android {
// --- AudioPort class implementation
void AudioPort::attach(const sp<HwModule>& module)
{
ALOGV("%s: attaching module %s to port %s", __FUNCTION__, getModuleName(), mName.string());
ALOGV("%s: attaching module %s to port %s", __FUNCTION__, getModuleName(), mName.c_str());
mModule = module;
}
@ -60,49 +60,6 @@ const char *AudioPort::getModuleName() const
return mModule != 0 ? mModule->getName() : "invalid module";
}
void AudioPort::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 : mProfiles) {
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", __FUNCTION__);
return;
}
}
}
port->role = mRole;
port->type = mType;
strlcpy(port->name, mName, 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 AudioPort::importAudioPort(const sp<AudioPort>& port, bool force __unused)
{
for (const auto& profileToImport : port->mProfiles) {
@ -324,40 +281,13 @@ void AudioPort::pickAudioProfile(uint32_t &samplingRate,
}
}
}
ALOGV("%s Port[nm:%s] profile rate=%d, format=%d, channels=%d", __FUNCTION__, mName.string(),
ALOGV("%s Port[nm:%s] profile rate=%d, format=%d, channels=%d", __FUNCTION__, mName.c_str(),
samplingRate, channelMask, format);
}
status_t AudioPort::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);
}
void AudioPort::dump(String8 *dst, int spaces, bool verbose) const
{
if (!mName.isEmpty()) {
dst->appendFormat("%*s- name: %s\n", spaces, "", mName.string());
}
if (verbose) {
mProfiles.dump(dst, spaces);
if (mGains.size() != 0) {
dst->appendFormat("%*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.c_str());
}
}
}
}
void AudioPort::log(const char* indent) const
{
ALOGI("%s Port[nm:%s, type:%d, role:%d]", indent, mName.string(), mType, mRole);
ALOGI("%s Port[nm:%s, type:%d, role:%d]", indent, mName.c_str(), mType, mRole);
}
// --- AudioPortConfig class implementation

@ -26,95 +26,31 @@
#include <utils/Errors.h>
#include "AudioPort.h"
#include "AudioProfile.h"
#include "AudioProfileVector.h"
#include "HwModule.h"
#include "TypeConverter.h"
#include "policy.h"
namespace android {
bool operator == (const AudioProfile &left, const AudioProfile &compareTo)
status_t checkExact(const sp<AudioProfile> &audioProfile, uint32_t samplingRate,
audio_channel_mask_t channelMask, audio_format_t format)
{
return (left.getFormat() == compareTo.getFormat()) &&
(left.getChannels() == compareTo.getChannels()) &&
(left.getSampleRates() == compareTo.getSampleRates());
}
static AudioProfile* createFullDynamicImpl()
{
AudioProfile* dynamicProfile = new AudioProfile(gDynamicFormat,
ChannelMaskSet(), SampleRateSet());
dynamicProfile->setDynamicFormat(true);
dynamicProfile->setDynamicChannels(true);
dynamicProfile->setDynamicRate(true);
return dynamicProfile;
}
// static
sp<AudioProfile> AudioProfile::createFullDynamic()
{
static sp<AudioProfile> dynamicProfile = createFullDynamicImpl();
return dynamicProfile;
}
AudioProfile::AudioProfile(audio_format_t format,
audio_channel_mask_t channelMasks,
uint32_t samplingRate) :
mName(String8("")),
mFormat(format)
{
mChannelMasks.insert(channelMasks);
mSamplingRates.insert(samplingRate);
}
AudioProfile::AudioProfile(audio_format_t format,
const ChannelMaskSet &channelMasks,
const SampleRateSet &samplingRateCollection) :
mName(String8("")),
mFormat(format),
mChannelMasks(channelMasks),
mSamplingRates(samplingRateCollection) {}
void AudioProfile::setChannels(const ChannelMaskSet &channelMasks)
{
if (mIsDynamicChannels) {
mChannelMasks = channelMasks;
}
}
void AudioProfile::setSampleRates(const SampleRateSet &sampleRates)
{
if (mIsDynamicRate) {
mSamplingRates = sampleRates;
}
}
void AudioProfile::clear()
{
if (mIsDynamicChannels) {
mChannelMasks.clear();
}
if (mIsDynamicRate) {
mSamplingRates.clear();
}
}
status_t AudioProfile::checkExact(uint32_t samplingRate, audio_channel_mask_t channelMask,
audio_format_t format) const
{
if (audio_formats_match(format, mFormat) &&
supportsChannels(channelMask) &&
supportsRate(samplingRate)) {
if (audio_formats_match(format, audioProfile->getFormat()) &&
audioProfile->supportsChannels(channelMask) &&
audioProfile->supportsRate(samplingRate)) {
return NO_ERROR;
}
return BAD_VALUE;
}
status_t AudioProfile::checkCompatibleSamplingRate(uint32_t samplingRate,
uint32_t &updatedSamplingRate) const
status_t checkCompatibleSamplingRate(const sp<AudioProfile> &audioProfile,
uint32_t samplingRate,
uint32_t &updatedSamplingRate)
{
ALOG_ASSERT(samplingRate > 0);
if (mSamplingRates.empty()) {
const SampleRateSet sampleRates = audioProfile->getSampleRates();
if (sampleRates.empty()) {
updatedSamplingRate = samplingRate;
return NO_ERROR;
}
@ -122,17 +58,17 @@ status_t AudioProfile::checkCompatibleSamplingRate(uint32_t samplingRate,
// Search for the closest supported sampling rate that is above (preferred)
// or below (acceptable) the desired sampling rate, within a permitted ratio.
// The sampling rates are sorted in ascending order.
auto desiredRate = mSamplingRates.lower_bound(samplingRate);
auto desiredRate = sampleRates.lower_bound(samplingRate);
// Prefer to down-sample from a higher sampling rate, as we get the desired frequency spectrum.
if (desiredRate != mSamplingRates.end()) {
if (desiredRate != sampleRates.end()) {
if (*desiredRate / AUDIO_RESAMPLER_DOWN_RATIO_MAX <= samplingRate) {
updatedSamplingRate = *desiredRate;
return NO_ERROR;
}
}
// But if we have to up-sample from a lower sampling rate, that's OK.
if (desiredRate != mSamplingRates.begin()) {
if (desiredRate != sampleRates.begin()) {
uint32_t candidate = *(--desiredRate);
if (candidate * AUDIO_RESAMPLER_UP_RATIO_MAX >= samplingRate) {
updatedSamplingRate = candidate;
@ -143,12 +79,14 @@ status_t AudioProfile::checkCompatibleSamplingRate(uint32_t samplingRate,
return BAD_VALUE;
}
status_t AudioProfile::checkCompatibleChannelMask(audio_channel_mask_t channelMask,
audio_channel_mask_t &updatedChannelMask,
audio_port_type_t portType,
audio_port_role_t portRole) const
status_t checkCompatibleChannelMask(const sp<AudioProfile> &audioProfile,
audio_channel_mask_t channelMask,
audio_channel_mask_t &updatedChannelMask,
audio_port_type_t portType,
audio_port_role_t portRole)
{
if (mChannelMasks.empty()) {
const ChannelMaskSet channelMasks = audioProfile->getChannels();
if (channelMasks.empty()) {
updatedChannelMask = channelMask;
return NO_ERROR;
}
@ -157,7 +95,7 @@ status_t AudioProfile::checkCompatibleChannelMask(audio_channel_mask_t channelMa
== AUDIO_CHANNEL_REPRESENTATION_INDEX;
const uint32_t channelCount = audio_channel_count_from_in_mask(channelMask);
int bestMatch = 0;
for (const auto &supported : mChannelMasks) {
for (const auto &supported : channelMasks) {
if (supported == channelMask) {
// Exact matches always taken.
updatedChannelMask = channelMask;
@ -235,37 +173,6 @@ status_t AudioProfile::checkCompatibleChannelMask(audio_channel_mask_t channelMa
return bestMatch > 0 ? NO_ERROR : BAD_VALUE;
}
void AudioProfile::dump(String8 *dst, int spaces) const
{
dst->appendFormat("%s%s%s\n", mIsDynamicFormat ? "[dynamic format]" : "",
mIsDynamicChannels ? "[dynamic channels]" : "",
mIsDynamicRate ? "[dynamic rates]" : "");
if (mName.length() != 0) {
dst->appendFormat("%*s- name: %s\n", spaces, "", mName.string());
}
std::string formatLiteral;
if (FormatConverter::toString(mFormat, formatLiteral)) {
dst->appendFormat("%*s- format: %s\n", spaces, "", formatLiteral.c_str());
}
if (!mSamplingRates.empty()) {
dst->appendFormat("%*s- sampling rates:", spaces, "");
for (auto it = mSamplingRates.begin(); it != mSamplingRates.end();) {
dst->appendFormat("%d", *it);
dst->append(++it == mSamplingRates.end() ? "" : ", ");
}
dst->append("\n");
}
if (!mChannelMasks.empty()) {
dst->appendFormat("%*s- channel masks:", spaces, "");
for (auto it = mChannelMasks.begin(); it != mChannelMasks.end();) {
dst->appendFormat("0x%04x", *it);
dst->append(++it == mChannelMasks.end() ? "" : ", ");
}
dst->append("\n");
}
}
ssize_t AudioProfileVector::add(const sp<AudioProfile> &profile)
{
ssize_t index = size();
@ -311,7 +218,7 @@ ssize_t AudioProfileVector::addProfileFromHal(const sp<AudioProfile> &profileToA
return add(profileToAdd);
}
status_t AudioProfileVector::checkExactProfile(uint32_t samplingRate,
status_t AudioProfileVector::checkExactProfile(const uint32_t samplingRate,
audio_channel_mask_t channelMask,
audio_format_t format) const
{
@ -320,7 +227,7 @@ status_t AudioProfileVector::checkExactProfile(uint32_t samplingRate,
}
for (const auto& profile : *this) {
if (profile->checkExact(samplingRate, channelMask, format) == NO_ERROR) {
if (checkExact(profile, samplingRate, channelMask, format) == NO_ERROR) {
return NO_ERROR;
}
}
@ -353,9 +260,9 @@ status_t AudioProfileVector::checkCompatibleProfile(uint32_t &samplingRate,
// rate and channels as well
audio_channel_mask_t updatedChannels;
uint32_t updatedRate;
if (profile->checkCompatibleChannelMask(channelMask, updatedChannels,
portType, portRole) == NO_ERROR &&
profile->checkCompatibleSamplingRate(samplingRate, updatedRate) == NO_ERROR) {
if (checkCompatibleChannelMask(profile, channelMask, updatedChannels,
portType, portRole) == NO_ERROR &&
checkCompatibleSamplingRate(profile, samplingRate, updatedRate) == NO_ERROR) {
// for inexact checks we take the first linear pcm format due to sorting.
format = formatToCompare;
channelMask = updatedChannels;
@ -367,18 +274,6 @@ status_t AudioProfileVector::checkCompatibleProfile(uint32_t &samplingRate,
return BAD_VALUE;
}
void AudioProfileVector::clearProfiles()
{
for (auto it = begin(); it != end();) {
if ((*it)->isDynamicFormat() && (*it)->hasValidFormat()) {
it = erase(it);
} else {
(*it)->clear();
++it;
}
}
}
// Returns an intersection between two possibly unsorted vectors and the contents of 'order'.
// The result is ordered according to 'order'.
template<typename T, typename Order>
@ -449,67 +344,6 @@ status_t AudioProfileVector::findBestMatchingOutputConfig(const AudioProfileVect
return BAD_VALUE;
}
sp<AudioProfile> AudioProfileVector::getFirstValidProfile() const
{
for (const auto &profile : *this) {
if (profile->isValid()) {
return profile;
}
}
return nullptr;
}
sp<AudioProfile> AudioProfileVector::getFirstValidProfileFor(audio_format_t format) const
{
for (const auto &profile : *this) {
if (profile->isValid() && profile->getFormat() == format) {
return profile;
}
}
return nullptr;
}
FormatVector AudioProfileVector::getSupportedFormats() const
{
FormatVector supportedFormats;
for (const auto &profile : *this) {
if (profile->hasValidFormat()) {
supportedFormats.push_back(profile->getFormat());
}
}
return supportedFormats;
}
bool AudioProfileVector::hasDynamicChannelsFor(audio_format_t format) const
{
for (const auto &profile : *this) {
if (profile->getFormat() == format && profile->isDynamicChannels()) {
return true;
}
}
return false;
}
bool AudioProfileVector::hasDynamicProfile() const
{
for (const auto &profile : *this) {
if (profile->isDynamic()) {
return true;
}
}
return false;
}
bool AudioProfileVector::hasDynamicRateFor(audio_format_t format) const
{
for (const auto &profile : *this) {
if (profile->getFormat() == format && profile->isDynamicRate()) {
return true;
}
}
return false;
}
void AudioProfileVector::setFormats(const FormatVector &formats)
{
// Only allow to change the format of dynamic profile
@ -528,15 +362,6 @@ void AudioProfileVector::setFormats(const FormatVector &formats)
}
}
void AudioProfileVector::dump(String8 *dst, int spaces) const
{
dst->appendFormat("%*s- Profiles:\n", spaces, "");
for (size_t i = 0; i < size(); i++) {
dst->appendFormat("%*sProfile %zu:", spaces + 4, "", i);
at(i)->dump(dst, spaces + 8);
}
}
sp<AudioProfile> AudioProfileVector::getProfileFor(audio_format_t format) const
{
for (const auto &profile : *this) {

@ -26,11 +26,11 @@ namespace android
void AudioRoute::dump(String8 *dst, int spaces) const
{
dst->appendFormat("%*s- Type: %s\n", spaces, "", mType == AUDIO_ROUTE_MUX ? "Mux" : "Mix");
dst->appendFormat("%*s- Sink: %s\n", spaces, "", mSink->getTagName().string());
dst->appendFormat("%*s- Sink: %s\n", spaces, "", mSink->getTagName().c_str());
if (mSources.size() != 0) {
dst->appendFormat("%*s- Sources: \n", spaces, "");
for (size_t i = 0; i < mSources.size(); i++) {
dst->appendFormat("%*s%s \n", spaces + 4, "", mSources[i]->getTagName().string());
dst->appendFormat("%*s%s \n", spaces + 4, "", mSources[i]->getTagName().c_str());
}
}
dst->append("\n");
@ -41,10 +41,10 @@ bool AudioRoute::supportsPatch(const sp<AudioPort> &srcPort, const sp<AudioPort>
if (mSink == 0 || dstPort == 0 || dstPort != mSink) {
return false;
}
ALOGV("%s: sinks %s matching", __FUNCTION__, mSink->getTagName().string());
ALOGV("%s: sinks %s matching", __FUNCTION__, mSink->getTagName().c_str());
for (const auto &sourcePort : mSources) {
if (sourcePort == srcPort) {
ALOGV("%s: sources %s matching", __FUNCTION__, sourcePort->getTagName().string());
ALOGV("%s: sources %s matching", __FUNCTION__, sourcePort->getTagName().c_str());
return true;
}
}

@ -26,14 +26,14 @@
namespace android {
DeviceDescriptor::DeviceDescriptor(audio_devices_t type, const String8 &tagName) :
DeviceDescriptor::DeviceDescriptor(audio_devices_t type, const std::string &tagName) :
DeviceDescriptor(type, FormatVector{}, tagName)
{
}
DeviceDescriptor::DeviceDescriptor(audio_devices_t type, const FormatVector &encodedFormats,
const String8 &tagName) :
AudioPort(String8(""), AUDIO_PORT_TYPE_DEVICE,
const std::string &tagName) :
AudioPort("", AUDIO_PORT_TYPE_DEVICE,
audio_is_output_device(type) ? AUDIO_PORT_ROLE_SINK :
AUDIO_PORT_ROLE_SOURCE),
mTagName(tagName), mDeviceType(type), mEncodedFormats(encodedFormats)
@ -255,7 +255,6 @@ DeviceVector DeviceVector::getDevicesFromTypeMask(audio_devices_t type) const
audio_devices_t curType = itemAt(i)->type() & ~AUDIO_DEVICE_BIT_IN;
if ((isOutput == curIsOutput) && ((type & curType) != 0)) {
devices.add(itemAt(i));
type &= ~curType;
ALOGV("DeviceVector::%s() for type %08x found %p",
__func__, itemAt(i)->type(), itemAt(i).get());
}
@ -263,7 +262,7 @@ DeviceVector DeviceVector::getDevicesFromTypeMask(audio_devices_t type) const
return devices;
}
sp<DeviceDescriptor> DeviceVector::getDeviceFromTagName(const String8 &tagName) const
sp<DeviceDescriptor> DeviceVector::getDeviceFromTagName(const std::string &tagName) const
{
for (const auto& device : *this) {
if (device->getTagName() == tagName) {
@ -273,6 +272,38 @@ sp<DeviceDescriptor> DeviceVector::getDeviceFromTagName(const String8 &tagName)
return nullptr;
}
DeviceVector DeviceVector::getFirstDevicesFromTypes(
std::vector<audio_devices_t> orderedTypes) const
{
DeviceVector devices;
for (auto deviceType : orderedTypes) {
if (!(devices = getDevicesFromTypeMask(deviceType)).isEmpty()) {
break;
}
}
return devices;
}
sp<DeviceDescriptor> DeviceVector::getFirstExistingDevice(
std::vector<audio_devices_t> orderedTypes) const {
sp<DeviceDescriptor> device;
for (auto deviceType : orderedTypes) {
if ((device = getDevice(deviceType, String8(""), AUDIO_FORMAT_DEFAULT)) != nullptr) {
break;
}
}
return device;
}
void DeviceVector::replaceDevicesByType(
audio_devices_t typeToRemove, const DeviceVector &devicesToAdd) {
DeviceVector devicesToRemove = getDevicesFromTypeMask(typeToRemove);
if (!devicesToRemove.isEmpty() && !devicesToAdd.isEmpty()) {
remove(devicesToRemove);
add(devicesToAdd);
}
}
void DeviceVector::dump(String8 *dst, const String8 &tag, int spaces, bool verbose) const
{
if (isEmpty()) {
@ -343,8 +374,8 @@ void DeviceDescriptor::dump(String8 *dst, int spaces, int index, bool verbose) c
if (mId != 0) {
dst->appendFormat("%*s- id: %2d\n", spaces, "", mId);
}
if (!mTagName.isEmpty()) {
dst->appendFormat("%*s- tag name: %s\n", spaces, "", mTagName.string());
if (!mTagName.empty()) {
dst->appendFormat("%*s- tag name: %s\n", spaces, "", mTagName.c_str());
}
dst->appendFormat("%*s- type: %-48s\n", spaces, "", ::android::toString(mDeviceType).c_str());
@ -352,7 +383,9 @@ void DeviceDescriptor::dump(String8 *dst, int spaces, int index, bool verbose) c
if (mAddress.size() != 0) {
dst->appendFormat("%*s- address: %-32s\n", spaces, "", mAddress.string());
}
AudioPort::dump(dst, spaces, verbose);
std::string portStr;
AudioPort::dump(&portStr, spaces, verbose);
dst->append(portStr.c_str());
}
std::string DeviceDescriptor::toString() const

@ -41,7 +41,7 @@ HwModule::~HwModule()
}
}
status_t HwModule::addOutputProfile(const String8& name, const audio_config_t *config,
status_t HwModule::addOutputProfile(const std::string& name, const audio_config_t *config,
audio_devices_t device, const String8& address)
{
sp<IOProfile> profile = new OutputProfile(name);
@ -95,7 +95,7 @@ void HwModule::setProfiles(const IOProfileCollection &profiles)
}
}
status_t HwModule::removeOutputProfile(const String8& name)
status_t HwModule::removeOutputProfile(const std::string& name)
{
for (size_t i = 0; i < mOutputProfiles.size(); i++) {
if (mOutputProfiles[i]->getName() == name) {
@ -110,7 +110,7 @@ status_t HwModule::removeOutputProfile(const String8& name)
return NO_ERROR;
}
status_t HwModule::addInputProfile(const String8& name, const audio_config_t *config,
status_t HwModule::addInputProfile(const std::string& name, const audio_config_t *config,
audio_devices_t device, const String8& address)
{
sp<IOProfile> profile = new InputProfile(name);
@ -125,12 +125,12 @@ status_t HwModule::addInputProfile(const String8& name, const audio_config_t *co
profile->addSupportedDevice(devDesc);
ALOGV("addInputProfile() name %s rate %d mask 0x%08x",
name.string(), config->sample_rate, config->channel_mask);
name.c_str(), config->sample_rate, config->channel_mask);
return addInputProfile(profile);
}
status_t HwModule::removeInputProfile(const String8& name)
status_t HwModule::removeInputProfile(const std::string& name)
{
for (size_t i = 0; i < mInputProfiles.size(); i++) {
if (mInputProfiles[i]->getName() == name) {
@ -193,13 +193,13 @@ void HwModule::refreshSupportedDevices()
}
DeviceVector sourceDevicesForRoute = getRouteSourceDevices(route);
if (sourceDevicesForRoute.isEmpty()) {
ALOGE("%s: invalid source devices for %s", __FUNCTION__, stream->getName().string());
ALOGE("%s: invalid source devices for %s", __FUNCTION__, stream->getName().c_str());
continue;
}
sourceDevices.add(sourceDevicesForRoute);
}
if (sourceDevices.isEmpty()) {
ALOGE("%s: invalid source devices for %s", __FUNCTION__, stream->getName().string());
ALOGE("%s: invalid source devices for %s", __FUNCTION__, stream->getName().c_str());
continue;
}
stream->setSupportedDevices(sourceDevices);
@ -214,7 +214,7 @@ void HwModule::refreshSupportedDevices()
}
sp<DeviceDescriptor> sinkDevice = getRouteSinkDevice(route);
if (sinkDevice == 0) {
ALOGE("%s: invalid sink device for %s", __FUNCTION__, stream->getName().string());
ALOGE("%s: invalid sink device for %s", __FUNCTION__, stream->getName().c_str());
continue;
}
sinkDevices.add(sinkDevice);
@ -335,7 +335,7 @@ sp<DeviceDescriptor> HwModuleCollection::getDeviceDescriptor(const audio_devices
if (allowToCreate) {
moduleDevice->attach(hwModule);
moduleDevice->setAddress(devAddress);
moduleDevice->setName(String8(name));
moduleDevice->setName(name);
}
return moduleDevice;
}
@ -359,8 +359,8 @@ sp<DeviceDescriptor> HwModuleCollection::createDevice(const audio_devices_t type
address);
return nullptr;
}
sp<DeviceDescriptor> device = new DeviceDescriptor(type, String8(name));
device->setName(String8(name));
sp<DeviceDescriptor> device = new DeviceDescriptor(type, name);
device->setName(name);
device->setAddress(String8(address));
device->setEncodedFormat(encodedFormat);

@ -107,7 +107,9 @@ bool IOProfile::isCompatibleProfile(const DeviceVector &devices,
void IOProfile::dump(String8 *dst) const
{
AudioPort::dump(dst, 4);
std::string portStr;
AudioPort::dump(&portStr, 4);
dst->append(portStr.c_str());
dst->appendFormat(" - flags: 0x%04x", getFlags());
std::string flagsLiteral;

@ -430,7 +430,7 @@ Return<MixPortTraits::Element> MixPortTraits::deserialize(const xmlNode *child,
audio_port_role_t portRole = (role == Attributes::roleSource) ?
AUDIO_PORT_ROLE_SOURCE : AUDIO_PORT_ROLE_SINK;
Element mixPort = new IOProfile(String8(name.c_str()), portRole);
Element mixPort = new IOProfile(name, portRole);
AudioProfileTraits::Collection profiles;
status_t status = deserializeCollection<AudioProfileTraits>(child, &profiles, NULL);
@ -438,7 +438,7 @@ Return<MixPortTraits::Element> MixPortTraits::deserialize(const xmlNode *child,
return Status::fromStatusT(status);
}
if (profiles.empty()) {
profiles.add(AudioProfile::createFullDynamic());
profiles.add(AudioProfile::createFullDynamic(gDynamicFormat));
}
mixPort->setAudioProfiles(profiles);
@ -508,7 +508,7 @@ Return<DevicePortTraits::Element> DevicePortTraits::deserialize(const xmlNode *c
if (!encodedFormatsLiteral.empty()) {
encodedFormats = formatsFromString(encodedFormatsLiteral, " ");
}
Element deviceDesc = new DeviceDescriptor(type, encodedFormats, String8(name.c_str()));
Element deviceDesc = new DeviceDescriptor(type, encodedFormats, name);
std::string address = getXmlAttribute(cur, Attributes::address);
if (!address.empty()) {
@ -522,7 +522,7 @@ Return<DevicePortTraits::Element> DevicePortTraits::deserialize(const xmlNode *c
return Status::fromStatusT(status);
}
if (profiles.empty()) {
profiles.add(AudioProfile::createFullDynamic());
profiles.add(AudioProfile::createFullDynamic(gDynamicFormat));
}
deviceDesc->setAudioProfiles(profiles);
@ -532,7 +532,7 @@ Return<DevicePortTraits::Element> DevicePortTraits::deserialize(const xmlNode *c
return Status::fromStatusT(status);
}
ALOGV("%s: adding device tag %s type %08x address %s", __func__,
deviceDesc->getName().string(), type, deviceDesc->address().string());
deviceDesc->getName().c_str(), type, deviceDesc->address().string());
return deviceDesc;
}
@ -555,7 +555,7 @@ Return<RouteTraits::Element> RouteTraits::deserialize(const xmlNode *cur, PtrSer
return Status::fromStatusT(BAD_VALUE);
}
// Convert Sink name to port pointer
sp<AudioPort> sink = ctx->findPortByTagName(String8(sinkAttr.c_str()));
sp<AudioPort> sink = ctx->findPortByTagName(sinkAttr);
if (sink == NULL) {
ALOGE("%s: no sink found with name=%s", __func__, sinkAttr.c_str());
return Status::fromStatusT(BAD_VALUE);
@ -574,7 +574,7 @@ Return<RouteTraits::Element> RouteTraits::deserialize(const xmlNode *cur, PtrSer
char *devTag = strtok(sourcesLiteral.get(), ",");
while (devTag != NULL) {
if (strlen(devTag) != 0) {
sp<AudioPort> source = ctx->findPortByTagName(String8(devTag));
sp<AudioPort> source = ctx->findPortByTagName(devTag);
if (source == NULL) {
ALOGE("%s: no source found with name=%s", __func__, devTag);
return Status::fromStatusT(BAD_VALUE);
@ -648,7 +648,7 @@ Return<ModuleTraits::Element> ModuleTraits::deserialize(const xmlNode *cur, PtrS
ALOGV("%s: %s %s=%s", __func__, tag, childAttachedDeviceTag,
reinterpret_cast<const char*>(attachedDevice.get()));
sp<DeviceDescriptor> device = module->getDeclaredDevices().
getDeviceFromTagName(String8(reinterpret_cast<const char*>(
getDeviceFromTagName(std::string(reinterpret_cast<const char*>(
attachedDevice.get())));
ctx->addAvailableDevice(device);
}
@ -663,7 +663,7 @@ Return<ModuleTraits::Element> ModuleTraits::deserialize(const xmlNode *cur, PtrS
ALOGV("%s: %s %s=%s", __func__, tag, childDefaultOutputDeviceTag,
reinterpret_cast<const char*>(defaultOutputDevice.get()));
sp<DeviceDescriptor> device = module->getDeclaredDevices().getDeviceFromTagName(
String8(reinterpret_cast<const char*>(defaultOutputDevice.get())));
std::string(reinterpret_cast<const char*>(defaultOutputDevice.get())));
if (device != 0 && ctx->getDefaultOutputDevice() == 0) {
ctx->setDefaultOutputDevice(device);
ALOGV("%s: default is %08x",

@ -136,27 +136,23 @@ status_t Engine::setForceUse(audio_policy_force_use_t usage, audio_policy_forced
return EngineBase::setForceUse(usage, config);
}
audio_devices_t Engine::getDeviceForStrategyInt(legacy_strategy strategy,
DeviceVector availableOutputDevices,
DeviceVector availableInputDevices,
const SwAudioOutputCollection &outputs,
uint32_t outputDeviceTypesToIgnore) const
DeviceVector Engine::getDevicesForStrategyInt(legacy_strategy strategy,
DeviceVector availableOutputDevices,
DeviceVector availableInputDevices,
const SwAudioOutputCollection &outputs) const
{
uint32_t device = AUDIO_DEVICE_NONE;
uint32_t availableOutputDevicesType =
availableOutputDevices.types() & ~outputDeviceTypesToIgnore;
DeviceVector devices;
switch (strategy) {
case STRATEGY_TRANSMITTED_THROUGH_SPEAKER:
device = availableOutputDevicesType & AUDIO_DEVICE_OUT_SPEAKER;
devices = availableOutputDevices.getDevicesFromTypeMask(AUDIO_DEVICE_OUT_SPEAKER);
break;
case STRATEGY_SONIFICATION_RESPECTFUL:
if (isInCall() || outputs.isActiveLocally(toVolumeSource(AUDIO_STREAM_VOICE_CALL))) {
device = getDeviceForStrategyInt(
STRATEGY_SONIFICATION, availableOutputDevices, availableInputDevices, outputs,
outputDeviceTypesToIgnore);
devices = getDevicesForStrategyInt(
STRATEGY_SONIFICATION, availableOutputDevices, availableInputDevices, outputs);
} else {
bool media_active_locally =
outputs.isActiveLocally(toVolumeSource(AUDIO_STREAM_MUSIC),
@ -165,17 +161,18 @@ audio_devices_t Engine::getDeviceForStrategyInt(legacy_strategy strategy,
toVolumeSource(AUDIO_STREAM_ACCESSIBILITY),
SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY);
// routing is same as media without the "remote" device
device = getDeviceForStrategyInt(STRATEGY_MEDIA,
availableOutputDevices.remove(availableOutputDevices.getDevicesFromTypeMask(
AUDIO_DEVICE_OUT_REMOTE_SUBMIX));
devices = getDevicesForStrategyInt(STRATEGY_MEDIA,
availableOutputDevices,
availableInputDevices, outputs,
AUDIO_DEVICE_OUT_REMOTE_SUBMIX | outputDeviceTypesToIgnore);
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
&& (device & AUDIO_DEVICE_OUT_SPEAKER)
&& (availableOutputDevicesType & AUDIO_DEVICE_OUT_SPEAKER_SAFE)) {
device |= AUDIO_DEVICE_OUT_SPEAKER_SAFE;
device &= ~AUDIO_DEVICE_OUT_SPEAKER;
if (!media_active_locally) {
devices.replaceDevicesByType(
AUDIO_DEVICE_OUT_SPEAKER,
availableOutputDevices.getDevicesFromTypeMask(
AUDIO_DEVICE_OUT_SPEAKER_SAFE));
}
}
break;
@ -183,9 +180,8 @@ audio_devices_t Engine::getDeviceForStrategyInt(legacy_strategy strategy,
case STRATEGY_DTMF:
if (!isInCall()) {
// when off call, DTMF strategy follows the same rules as MEDIA strategy
device = getDeviceForStrategyInt(
STRATEGY_MEDIA, availableOutputDevices, availableInputDevices, outputs,
outputDeviceTypesToIgnore);
devices = getDevicesForStrategyInt(
STRATEGY_MEDIA, availableOutputDevices, availableInputDevices, outputs);
break;
}
// when in call, DTMF and PHONE strategies follow the same rules
@ -197,24 +193,27 @@ audio_devices_t Engine::getDeviceForStrategyInt(legacy_strategy strategy,
// - cannot route from voice call RX OR
// - audio HAL version is < 3.0 and TX device is on the primary HW module
if (getPhoneState() == AUDIO_MODE_IN_CALL) {
audio_devices_t txDevice = getDeviceForInputSource(AUDIO_SOURCE_VOICE_COMMUNICATION);
audio_devices_t txDevice = getDeviceForInputSource(
AUDIO_SOURCE_VOICE_COMMUNICATION)->type();
sp<AudioOutputDescriptor> primaryOutput = outputs.getPrimaryOutput();
audio_devices_t availPrimaryInputDevices =
availableInputDevices.getDeviceTypesFromHwModule(primaryOutput->getModuleHandle());
DeviceVector availPrimaryInputDevices =
availableInputDevices.getDevicesFromHwModule(primaryOutput->getModuleHandle());
// TODO: getPrimaryOutput return only devices from first module in
// audio_policy_configuration.xml, hearing aid is not there, but it's
// a primary device
// FIXME: this is not the right way of solving this problem
audio_devices_t availPrimaryOutputDevices =
(primaryOutput->supportedDevices().types() | AUDIO_DEVICE_OUT_HEARING_AID) &
availableOutputDevices.types();
if (((availableInputDevices.types() &
AUDIO_DEVICE_IN_TELEPHONY_RX & ~AUDIO_DEVICE_BIT_IN) == 0) ||
(((txDevice & availPrimaryInputDevices & ~AUDIO_DEVICE_BIT_IN) != 0) &&
(primaryOutput->getAudioPort()->getModuleVersionMajor() < 3))) {
availableOutputDevicesType = availPrimaryOutputDevices;
DeviceVector availPrimaryOutputDevices = availableOutputDevices.getDevicesFromTypeMask(
primaryOutput->supportedDevices().types());
availPrimaryOutputDevices.add(
availableOutputDevices.getDevicesFromTypeMask(AUDIO_DEVICE_OUT_HEARING_AID));
if ((availableInputDevices.getDevice(AUDIO_DEVICE_IN_TELEPHONY_RX,
String8(""), AUDIO_FORMAT_DEFAULT) == nullptr) ||
((availPrimaryInputDevices.getDevice(
txDevice, String8(""), AUDIO_FORMAT_DEFAULT) != nullptr) &&
(primaryOutput->getAudioPort()->getModuleVersionMajor() < 3))) {
availableOutputDevices = availPrimaryOutputDevices;
}
}
// for phone strategy, we first consider the forced use and then the available devices by
@ -222,49 +221,40 @@ audio_devices_t Engine::getDeviceForStrategyInt(legacy_strategy strategy,
switch (getForceUse(AUDIO_POLICY_FORCE_FOR_COMMUNICATION)) {
case AUDIO_POLICY_FORCE_BT_SCO:
if (!isInCall() || strategy != STRATEGY_DTMF) {
device = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
if (device) break;
devices = availableOutputDevices.getDevicesFromTypeMask(
AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT);
if (!devices.isEmpty()) break;
}
device = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
if (device) break;
device = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_SCO;
if (device) break;
devices = availableOutputDevices.getFirstDevicesFromTypes({
AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET, AUDIO_DEVICE_OUT_BLUETOOTH_SCO});
if (!devices.isEmpty()) break;
// if SCO device is requested but no SCO device is available, fall back to default case
FALLTHROUGH_INTENDED;
default: // FORCE_NONE
device = availableOutputDevicesType & AUDIO_DEVICE_OUT_HEARING_AID;
if (device) break;
devices = availableOutputDevices.getDevicesFromTypeMask(AUDIO_DEVICE_OUT_HEARING_AID);
if (!devices.isEmpty()) break;
// when not in a phone call, phone strategy should route STREAM_VOICE_CALL to A2DP
if (!isInCall() &&
(getForceUse(AUDIO_POLICY_FORCE_FOR_MEDIA) != AUDIO_POLICY_FORCE_NO_BT_A2DP) &&
outputs.isA2dpSupported()) {
device = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP;
if (device) break;
device = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES;
if (device) break;
devices = availableOutputDevices.getFirstDevicesFromTypes({
AUDIO_DEVICE_OUT_BLUETOOTH_A2DP,
AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES});
if (!devices.isEmpty()) break;
}
device = availableOutputDevicesType & AUDIO_DEVICE_OUT_WIRED_HEADPHONE;
if (device) break;
device = availableOutputDevicesType & AUDIO_DEVICE_OUT_WIRED_HEADSET;
if (device) break;
device = availableOutputDevicesType & AUDIO_DEVICE_OUT_LINE;
if (device) break;
device = availableOutputDevicesType & AUDIO_DEVICE_OUT_USB_HEADSET;
if (device) break;
device = availableOutputDevicesType & AUDIO_DEVICE_OUT_USB_DEVICE;
if (device) break;
devices = availableOutputDevices.getFirstDevicesFromTypes({
AUDIO_DEVICE_OUT_WIRED_HEADPHONE, AUDIO_DEVICE_OUT_WIRED_HEADSET,
AUDIO_DEVICE_OUT_LINE, AUDIO_DEVICE_OUT_USB_HEADSET,
AUDIO_DEVICE_OUT_USB_DEVICE});
if (!devices.isEmpty()) break;
if (!isInCall()) {
device = availableOutputDevicesType & AUDIO_DEVICE_OUT_USB_ACCESSORY;
if (device) break;
device = availableOutputDevicesType & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET;
if (device) break;
device = availableOutputDevicesType & AUDIO_DEVICE_OUT_AUX_DIGITAL;
if (device) break;
device = availableOutputDevicesType & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET;
if (device) break;
devices = availableOutputDevices.getFirstDevicesFromTypes({
AUDIO_DEVICE_OUT_USB_ACCESSORY, AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET,
AUDIO_DEVICE_OUT_AUX_DIGITAL, AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET});
if (!devices.isEmpty()) break;
}
device = availableOutputDevicesType & AUDIO_DEVICE_OUT_EARPIECE;
devices = availableOutputDevices.getDevicesFromTypeMask(AUDIO_DEVICE_OUT_EARPIECE);
break;
case AUDIO_POLICY_FORCE_SPEAKER:
@ -273,22 +263,18 @@ audio_devices_t Engine::getDeviceForStrategyInt(legacy_strategy strategy,
if (!isInCall() &&
(getForceUse(AUDIO_POLICY_FORCE_FOR_MEDIA) != AUDIO_POLICY_FORCE_NO_BT_A2DP) &&
outputs.isA2dpSupported()) {
device = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER;
if (device) break;
devices = availableOutputDevices.getDevicesFromTypeMask(
AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER);
if (!devices.isEmpty()) break;
}
if (!isInCall()) {
device = availableOutputDevicesType & AUDIO_DEVICE_OUT_USB_ACCESSORY;
if (device) break;
device = availableOutputDevicesType & AUDIO_DEVICE_OUT_USB_DEVICE;
if (device) break;
device = availableOutputDevicesType & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET;
if (device) break;
device = availableOutputDevicesType & AUDIO_DEVICE_OUT_AUX_DIGITAL;
if (device) break;
device = availableOutputDevicesType & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET;
if (device) break;
devices = availableOutputDevices.getFirstDevicesFromTypes({
AUDIO_DEVICE_OUT_USB_ACCESSORY, AUDIO_DEVICE_OUT_USB_DEVICE,
AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET, AUDIO_DEVICE_OUT_AUX_DIGITAL,
AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET});
if (!devices.isEmpty()) break;
}
device = availableOutputDevicesType & AUDIO_DEVICE_OUT_SPEAKER;
devices = availableOutputDevices.getDevicesFromTypeMask(AUDIO_DEVICE_OUT_SPEAKER);
break;
}
break;
@ -298,9 +284,8 @@ audio_devices_t Engine::getDeviceForStrategyInt(legacy_strategy strategy,
// If incall, just select the STRATEGY_PHONE device
if (isInCall() ||
outputs.isActiveLocally(toVolumeSource(AUDIO_STREAM_VOICE_CALL))) {
device = getDeviceForStrategyInt(
STRATEGY_PHONE, availableOutputDevices, availableInputDevices, outputs,
outputDeviceTypesToIgnore);
devices = getDevicesForStrategyInt(
STRATEGY_PHONE, availableOutputDevices, availableInputDevices, outputs);
break;
}
FALLTHROUGH_INTENDED;
@ -313,41 +298,37 @@ audio_devices_t Engine::getDeviceForStrategyInt(legacy_strategy strategy,
if ((strategy == STRATEGY_SONIFICATION) ||
(getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) == AUDIO_POLICY_FORCE_SYSTEM_ENFORCED)) {
device = availableOutputDevicesType & AUDIO_DEVICE_OUT_SPEAKER;
devices = availableOutputDevices.getDevicesFromTypeMask(AUDIO_DEVICE_OUT_SPEAKER);
}
// if SCO headset is connected and we are told to use it, play ringtone over
// speaker and BT SCO
if ((availableOutputDevicesType & AUDIO_DEVICE_OUT_ALL_SCO) != 0) {
uint32_t device2 = AUDIO_DEVICE_NONE;
device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
if (device2 == AUDIO_DEVICE_NONE) {
device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
}
if (device2 == AUDIO_DEVICE_NONE) {
device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_SCO;
}
if (!availableOutputDevices.getDevicesFromTypeMask(AUDIO_DEVICE_OUT_ALL_SCO).isEmpty()) {
DeviceVector devices2;
devices2 = availableOutputDevices.getFirstDevicesFromTypes({
AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT, AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET,
AUDIO_DEVICE_OUT_BLUETOOTH_SCO});
// Use ONLY Bluetooth SCO output when ringing in vibration mode
if (!((getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) == AUDIO_POLICY_FORCE_SYSTEM_ENFORCED)
&& (strategy == STRATEGY_ENFORCED_AUDIBLE))) {
if (getForceUse(AUDIO_POLICY_FORCE_FOR_VIBRATE_RINGING)
== AUDIO_POLICY_FORCE_BT_SCO) {
if (device2 != AUDIO_DEVICE_NONE) {
device = device2;
if (!devices2.isEmpty()) {
devices = devices2;
break;
}
}
}
// Use both Bluetooth SCO and phone default output when ringing in normal mode
if (getForceUse(AUDIO_POLICY_FORCE_FOR_COMMUNICATION) == AUDIO_POLICY_FORCE_BT_SCO) {
if ((strategy == STRATEGY_SONIFICATION) &&
(device & AUDIO_DEVICE_OUT_SPEAKER) &&
(availableOutputDevicesType & AUDIO_DEVICE_OUT_SPEAKER_SAFE)) {
device |= AUDIO_DEVICE_OUT_SPEAKER_SAFE;
device &= ~AUDIO_DEVICE_OUT_SPEAKER;
if (strategy == STRATEGY_SONIFICATION) {
devices.replaceDevicesByType(
AUDIO_DEVICE_OUT_SPEAKER,
availableOutputDevices.getDevicesFromTypeMask(
AUDIO_DEVICE_OUT_SPEAKER_SAFE));
}
if (device2 != AUDIO_DEVICE_NONE) {
device |= device2;
if (!devices2.isEmpty()) {
devices.add(devices2);
break;
}
}
@ -361,25 +342,20 @@ audio_devices_t Engine::getDeviceForStrategyInt(legacy_strategy strategy,
// compressed format as they would likely not be mixed and dropped.
for (size_t i = 0; i < outputs.size(); i++) {
sp<AudioOutputDescriptor> desc = outputs.valueAt(i);
audio_devices_t devices = desc->devices().types() &
(AUDIO_DEVICE_OUT_HDMI | AUDIO_DEVICE_OUT_SPDIF | AUDIO_DEVICE_OUT_HDMI_ARC);
if (desc->isActive() && !audio_is_linear_pcm(desc->mFormat) &&
devices != AUDIO_DEVICE_NONE) {
availableOutputDevicesType = availableOutputDevices.types() & ~devices;
if (desc->isActive() && !audio_is_linear_pcm(desc->getFormat())) {
availableOutputDevices.remove(desc->devices().getDevicesFromTypeMask(
AUDIO_DEVICE_OUT_HDMI | AUDIO_DEVICE_OUT_SPDIF
| AUDIO_DEVICE_OUT_HDMI_ARC));
}
}
availableOutputDevices =
availableOutputDevices.getDevicesFromTypeMask(availableOutputDevicesType);
if (outputs.isActive(toVolumeSource(AUDIO_STREAM_RING)) ||
outputs.isActive(toVolumeSource(AUDIO_STREAM_ALARM))) {
return getDeviceForStrategyInt(
STRATEGY_SONIFICATION, availableOutputDevices, availableInputDevices, outputs,
outputDeviceTypesToIgnore);
return getDevicesForStrategyInt(
STRATEGY_SONIFICATION, availableOutputDevices, availableInputDevices, outputs);
}
if (isInCall()) {
return getDeviceForStrategyInt(
STRATEGY_PHONE, availableOutputDevices, availableInputDevices, outputs,
outputDeviceTypesToIgnore);
return getDevicesForStrategyInt(
STRATEGY_PHONE, availableOutputDevices, availableInputDevices, outputs);
}
}
// For other cases, STRATEGY_ACCESSIBILITY behaves like STRATEGY_MEDIA
@ -388,128 +364,116 @@ audio_devices_t Engine::getDeviceForStrategyInt(legacy_strategy strategy,
// FIXME: STRATEGY_REROUTING follow STRATEGY_MEDIA for now
case STRATEGY_REROUTING:
case STRATEGY_MEDIA: {
uint32_t device2 = AUDIO_DEVICE_NONE;
DeviceVector devices2;
if (strategy != STRATEGY_SONIFICATION) {
// no sonification on remote submix (e.g. WFD)
if (availableOutputDevices.getDevice(AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
String8("0"), AUDIO_FORMAT_DEFAULT) != 0) {
device2 = availableOutputDevices.types() & AUDIO_DEVICE_OUT_REMOTE_SUBMIX;
sp<DeviceDescriptor> remoteSubmix;
if ((remoteSubmix = availableOutputDevices.getDevice(
AUDIO_DEVICE_OUT_REMOTE_SUBMIX, String8("0"),
AUDIO_FORMAT_DEFAULT)) != nullptr) {
devices2.add(remoteSubmix);
}
}
if (isInCall() && (strategy == STRATEGY_MEDIA)) {
device = getDeviceForStrategyInt(
STRATEGY_PHONE, availableOutputDevices, availableInputDevices, outputs,
outputDeviceTypesToIgnore);
devices = getDevicesForStrategyInt(
STRATEGY_PHONE, availableOutputDevices, availableInputDevices, outputs);
break;
}
// FIXME: Find a better solution to prevent routing to BT hearing aid(b/122931261).
if ((device2 == AUDIO_DEVICE_NONE) &&
if ((devices2.isEmpty()) &&
(getForceUse(AUDIO_POLICY_FORCE_FOR_MEDIA) != AUDIO_POLICY_FORCE_NO_BT_A2DP)) {
device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_HEARING_AID;
devices2 = availableOutputDevices.getDevicesFromTypeMask(AUDIO_DEVICE_OUT_HEARING_AID);
}
if ((device2 == AUDIO_DEVICE_NONE) &&
if ((devices2.isEmpty()) &&
(getForceUse(AUDIO_POLICY_FORCE_FOR_MEDIA) != AUDIO_POLICY_FORCE_NO_BT_A2DP) &&
outputs.isA2dpSupported()) {
device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP;
if (device2 == AUDIO_DEVICE_NONE) {
device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES;
}
if (device2 == AUDIO_DEVICE_NONE) {
device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER;
}
devices2 = availableOutputDevices.getFirstDevicesFromTypes({
AUDIO_DEVICE_OUT_BLUETOOTH_A2DP, AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES,
AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER});
}
if ((device2 == AUDIO_DEVICE_NONE) &&
if ((devices2.isEmpty()) &&
(getForceUse(AUDIO_POLICY_FORCE_FOR_MEDIA) == AUDIO_POLICY_FORCE_SPEAKER)) {
device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_SPEAKER;
}
if (device2 == AUDIO_DEVICE_NONE) {
device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_WIRED_HEADPHONE;
}
if (device2 == AUDIO_DEVICE_NONE) {
device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_LINE;
}
if (device2 == AUDIO_DEVICE_NONE) {
device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_WIRED_HEADSET;
}
if (device2 == AUDIO_DEVICE_NONE) {
device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_USB_HEADSET;
devices2 = availableOutputDevices.getDevicesFromTypeMask(AUDIO_DEVICE_OUT_SPEAKER);
}
if (device2 == AUDIO_DEVICE_NONE) {
device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_USB_ACCESSORY;
if (devices2.isEmpty()) {
devices2 = availableOutputDevices.getFirstDevicesFromTypes({
AUDIO_DEVICE_OUT_WIRED_HEADPHONE, AUDIO_DEVICE_OUT_LINE,
AUDIO_DEVICE_OUT_WIRED_HEADSET, AUDIO_DEVICE_OUT_USB_HEADSET,
AUDIO_DEVICE_OUT_USB_ACCESSORY, AUDIO_DEVICE_OUT_USB_DEVICE,
AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET});
}
if (device2 == AUDIO_DEVICE_NONE) {
device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_USB_DEVICE;
}
if (device2 == AUDIO_DEVICE_NONE) {
device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET;
}
if ((device2 == AUDIO_DEVICE_NONE) && (strategy != STRATEGY_SONIFICATION)) {
if ((devices2.isEmpty()) && (strategy != STRATEGY_SONIFICATION)) {
// no sonification on aux digital (e.g. HDMI)
device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_AUX_DIGITAL;
devices2 = availableOutputDevices.getDevicesFromTypeMask(AUDIO_DEVICE_OUT_AUX_DIGITAL);
}
if ((device2 == AUDIO_DEVICE_NONE) &&
if ((devices2.isEmpty()) &&
(getForceUse(AUDIO_POLICY_FORCE_FOR_DOCK) == AUDIO_POLICY_FORCE_ANALOG_DOCK)) {
device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET;
devices2 = availableOutputDevices.getDevicesFromTypeMask(
AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET);
}
if (device2 == AUDIO_DEVICE_NONE) {
device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_SPEAKER;
if (devices2.isEmpty()) {
devices2 = availableOutputDevices.getDevicesFromTypeMask(AUDIO_DEVICE_OUT_SPEAKER);
}
int device3 = AUDIO_DEVICE_NONE;
DeviceVector devices3;
if (strategy == STRATEGY_MEDIA) {
// ARC, SPDIF and AUX_LINE can co-exist with others.
device3 = availableOutputDevicesType & AUDIO_DEVICE_OUT_HDMI_ARC;
device3 |= (availableOutputDevicesType & AUDIO_DEVICE_OUT_SPDIF);
device3 |= (availableOutputDevicesType & AUDIO_DEVICE_OUT_AUX_LINE);
devices3 = availableOutputDevices.getDevicesFromTypeMask(
AUDIO_DEVICE_OUT_HDMI_ARC | AUDIO_DEVICE_OUT_SPDIF | AUDIO_DEVICE_OUT_AUX_LINE);
}
device2 |= device3;
devices2.add(devices3);
// device is DEVICE_OUT_SPEAKER if we come from case STRATEGY_SONIFICATION or
// STRATEGY_ENFORCED_AUDIBLE, AUDIO_DEVICE_NONE otherwise
device |= device2;
devices.add(devices2);
// If hdmi system audio mode is on, remove speaker out of output list.
if ((strategy == STRATEGY_MEDIA) &&
(getForceUse(AUDIO_POLICY_FORCE_FOR_HDMI_SYSTEM_AUDIO) ==
AUDIO_POLICY_FORCE_HDMI_SYSTEM_AUDIO_ENFORCED)) {
device &= ~AUDIO_DEVICE_OUT_SPEAKER;
devices.remove(devices.getDevicesFromTypeMask(AUDIO_DEVICE_OUT_SPEAKER));
}
// for STRATEGY_SONIFICATION:
// if SPEAKER was selected, and SPEAKER_SAFE is available, use SPEAKER_SAFE instead
if ((strategy == STRATEGY_SONIFICATION) &&
(device & AUDIO_DEVICE_OUT_SPEAKER) &&
(availableOutputDevicesType & AUDIO_DEVICE_OUT_SPEAKER_SAFE)) {
device |= AUDIO_DEVICE_OUT_SPEAKER_SAFE;
device &= ~AUDIO_DEVICE_OUT_SPEAKER;
if (strategy == STRATEGY_SONIFICATION) {
devices.replaceDevicesByType(
AUDIO_DEVICE_OUT_SPEAKER,
availableOutputDevices.getDevicesFromTypeMask(
AUDIO_DEVICE_OUT_SPEAKER_SAFE));
}
} break;
default:
ALOGW("getDeviceForStrategy() unknown strategy: %d", strategy);
ALOGW("getDevicesForStrategy() unknown strategy: %d", strategy);
break;
}
if (device == AUDIO_DEVICE_NONE) {
ALOGV("getDeviceForStrategy() no device found for strategy %d", strategy);
device = getApmObserver()->getDefaultOutputDevice()->type();
ALOGE_IF(device == AUDIO_DEVICE_NONE,
"getDeviceForStrategy() no default device defined");
if (devices.isEmpty()) {
ALOGV("getDevicesForStrategy() no device found for strategy %d", strategy);
sp<DeviceDescriptor> defaultOutputDevice = getApmObserver()->getDefaultOutputDevice();
if (defaultOutputDevice != nullptr) {
devices.add(defaultOutputDevice);
}
ALOGE_IF(devices.isEmpty(),
"getDevicesForStrategy() no default device defined");
}
ALOGVV("getDeviceForStrategy() strategy %d, device %x", strategy, device);
return device;
ALOGVV("getDevices"
"ForStrategy() strategy %d, device %x", strategy, devices.types());
return devices;
}
audio_devices_t Engine::getDeviceForInputSource(audio_source_t inputSource) const
sp<DeviceDescriptor> Engine::getDeviceForInputSource(audio_source_t inputSource) const
{
const DeviceVector availableOutputDevices = getApmObserver()->getAvailableOutputDevices();
const DeviceVector availableInputDevices = getApmObserver()->getAvailableInputDevices();
const SwAudioOutputCollection &outputs = getApmObserver()->getOutputs();
audio_devices_t availableDeviceTypes = availableInputDevices.types() & ~AUDIO_DEVICE_BIT_IN;
DeviceVector availableDevices = availableInputDevices;
sp<AudioOutputDescriptor> primaryOutput = outputs.getPrimaryOutput();
audio_devices_t availablePrimaryDeviceTypes = availableInputDevices.getDeviceTypesFromHwModule(
primaryOutput->getModuleHandle()) & ~AUDIO_DEVICE_BIT_IN;
uint32_t device = AUDIO_DEVICE_NONE;
DeviceVector availablePrimaryDevices = availableInputDevices.getDevicesFromHwModule(
primaryOutput->getModuleHandle());
sp<DeviceDescriptor> device;
// when a call is active, force device selection to match source VOICE_COMMUNICATION
// for most other input sources to avoid rerouting call TX audio
@ -532,57 +496,47 @@ audio_devices_t Engine::getDeviceForInputSource(audio_source_t inputSource) cons
switch (inputSource) {
case AUDIO_SOURCE_DEFAULT:
case AUDIO_SOURCE_MIC:
if (availableDeviceTypes & AUDIO_DEVICE_IN_BLUETOOTH_A2DP) {
device = AUDIO_DEVICE_IN_BLUETOOTH_A2DP;
} else if ((getForceUse(AUDIO_POLICY_FORCE_FOR_RECORD) == AUDIO_POLICY_FORCE_BT_SCO) &&
(availableDeviceTypes & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET)) {
device = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET;
} else if (availableDeviceTypes & AUDIO_DEVICE_IN_WIRED_HEADSET) {
device = AUDIO_DEVICE_IN_WIRED_HEADSET;
} else if (availableDeviceTypes & AUDIO_DEVICE_IN_USB_HEADSET) {
device = AUDIO_DEVICE_IN_USB_HEADSET;
} else if (availableDeviceTypes & AUDIO_DEVICE_IN_USB_DEVICE) {
device = AUDIO_DEVICE_IN_USB_DEVICE;
} else if (availableDeviceTypes & AUDIO_DEVICE_IN_BUILTIN_MIC) {
device = AUDIO_DEVICE_IN_BUILTIN_MIC;
}
break;
device = availableDevices.getDevice(
AUDIO_DEVICE_IN_BLUETOOTH_A2DP, String8(""), AUDIO_FORMAT_DEFAULT);
if (device != nullptr) break;
if (getForceUse(AUDIO_POLICY_FORCE_FOR_RECORD) == AUDIO_POLICY_FORCE_BT_SCO) {
device = availableDevices.getDevice(
AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET, String8(""), AUDIO_FORMAT_DEFAULT);
if (device != nullptr) break;
}
device = availableDevices.getFirstExistingDevice({
AUDIO_DEVICE_IN_WIRED_HEADSET, AUDIO_DEVICE_IN_USB_HEADSET,
AUDIO_DEVICE_IN_USB_DEVICE, AUDIO_DEVICE_IN_BUILTIN_MIC});
break;
case AUDIO_SOURCE_VOICE_COMMUNICATION:
// Allow only use of devices on primary input if in call and HAL does not support routing
// to voice call path.
if ((getPhoneState() == AUDIO_MODE_IN_CALL) &&
(availableOutputDevices.types() & AUDIO_DEVICE_OUT_TELEPHONY_TX) == 0) {
availableDeviceTypes = availablePrimaryDeviceTypes;
(availableOutputDevices.getDevice(AUDIO_DEVICE_OUT_TELEPHONY_TX,
String8(""), AUDIO_FORMAT_DEFAULT)) == nullptr) {
availableDevices = availablePrimaryDevices;
}
switch (getForceUse(AUDIO_POLICY_FORCE_FOR_COMMUNICATION)) {
case AUDIO_POLICY_FORCE_BT_SCO:
// if SCO device is requested but no SCO device is available, fall back to default case
if (availableDeviceTypes & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) {
device = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET;
device = availableDevices.getDevice(
AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET, String8(""), AUDIO_FORMAT_DEFAULT);
if (device != nullptr) {
break;
}
FALLTHROUGH_INTENDED;
default: // FORCE_NONE
if (availableDeviceTypes & AUDIO_DEVICE_IN_WIRED_HEADSET) {
device = AUDIO_DEVICE_IN_WIRED_HEADSET;
} else if (availableDeviceTypes & AUDIO_DEVICE_IN_USB_HEADSET) {
device = AUDIO_DEVICE_IN_USB_HEADSET;
} else if (availableDeviceTypes & AUDIO_DEVICE_IN_USB_DEVICE) {
device = AUDIO_DEVICE_IN_USB_DEVICE;
} else if (availableDeviceTypes & AUDIO_DEVICE_IN_BUILTIN_MIC) {
device = AUDIO_DEVICE_IN_BUILTIN_MIC;
}
device = availableDevices.getFirstExistingDevice({
AUDIO_DEVICE_IN_WIRED_HEADSET, AUDIO_DEVICE_IN_USB_HEADSET,
AUDIO_DEVICE_IN_USB_DEVICE, AUDIO_DEVICE_IN_BUILTIN_MIC});
break;
case AUDIO_POLICY_FORCE_SPEAKER:
if (availableDeviceTypes & AUDIO_DEVICE_IN_BACK_MIC) {
device = AUDIO_DEVICE_IN_BACK_MIC;
} else if (availableDeviceTypes & AUDIO_DEVICE_IN_BUILTIN_MIC) {
device = AUDIO_DEVICE_IN_BUILTIN_MIC;
}
device = availableDevices.getFirstExistingDevice({
AUDIO_DEVICE_IN_BACK_MIC, AUDIO_DEVICE_IN_BUILTIN_MIC});
break;
}
break;
@ -591,77 +545,60 @@ audio_devices_t Engine::getDeviceForInputSource(audio_source_t inputSource) cons
case AUDIO_SOURCE_UNPROCESSED:
case AUDIO_SOURCE_HOTWORD:
if (inputSource == AUDIO_SOURCE_HOTWORD) {
availableDeviceTypes = availablePrimaryDeviceTypes;
}
if (getForceUse(AUDIO_POLICY_FORCE_FOR_RECORD) == AUDIO_POLICY_FORCE_BT_SCO &&
availableDeviceTypes & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) {
device = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET;
} else if (availableDeviceTypes & AUDIO_DEVICE_IN_WIRED_HEADSET) {
device = AUDIO_DEVICE_IN_WIRED_HEADSET;
} else if (availableDeviceTypes & AUDIO_DEVICE_IN_USB_HEADSET) {
device = AUDIO_DEVICE_IN_USB_HEADSET;
} else if (availableDeviceTypes & AUDIO_DEVICE_IN_USB_DEVICE) {
device = AUDIO_DEVICE_IN_USB_DEVICE;
} else if (availableDeviceTypes & AUDIO_DEVICE_IN_BUILTIN_MIC) {
device = AUDIO_DEVICE_IN_BUILTIN_MIC;
availableDevices = availablePrimaryDevices;
}
if (getForceUse(AUDIO_POLICY_FORCE_FOR_RECORD) == AUDIO_POLICY_FORCE_BT_SCO) {
device = availableDevices.getDevice(
AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET, String8(""), AUDIO_FORMAT_DEFAULT);
if (device != nullptr) break;
}
device = availableDevices.getFirstExistingDevice({
AUDIO_DEVICE_IN_WIRED_HEADSET, AUDIO_DEVICE_IN_USB_HEADSET,
AUDIO_DEVICE_IN_USB_DEVICE, AUDIO_DEVICE_IN_BUILTIN_MIC});
break;
case AUDIO_SOURCE_CAMCORDER:
if (availableDeviceTypes & AUDIO_DEVICE_IN_BACK_MIC) {
device = AUDIO_DEVICE_IN_BACK_MIC;
} else if (availableDeviceTypes & AUDIO_DEVICE_IN_BUILTIN_MIC) {
device = AUDIO_DEVICE_IN_BUILTIN_MIC;
} else if (availableDeviceTypes & AUDIO_DEVICE_IN_USB_DEVICE) {
// This is specifically for a device without built-in mic
device = AUDIO_DEVICE_IN_USB_DEVICE;
}
// For a device without built-in mic, adding usb device
device = availableDevices.getFirstExistingDevice({
AUDIO_DEVICE_IN_BACK_MIC, AUDIO_DEVICE_IN_BUILTIN_MIC,
AUDIO_DEVICE_IN_USB_DEVICE});
break;
case AUDIO_SOURCE_VOICE_DOWNLINK:
case AUDIO_SOURCE_VOICE_CALL:
case AUDIO_SOURCE_VOICE_UPLINK:
if (availableDeviceTypes & AUDIO_DEVICE_IN_VOICE_CALL) {
device = AUDIO_DEVICE_IN_VOICE_CALL;
}
device = availableDevices.getDevice(
AUDIO_DEVICE_IN_VOICE_CALL, String8(""), AUDIO_FORMAT_DEFAULT);
break;
case AUDIO_SOURCE_VOICE_PERFORMANCE:
if (availableDeviceTypes & AUDIO_DEVICE_IN_WIRED_HEADSET) {
device = AUDIO_DEVICE_IN_WIRED_HEADSET;
} else if (availableDeviceTypes & AUDIO_DEVICE_IN_USB_HEADSET) {
device = AUDIO_DEVICE_IN_USB_HEADSET;
} else if (availableDeviceTypes & AUDIO_DEVICE_IN_USB_DEVICE) {
device = AUDIO_DEVICE_IN_USB_DEVICE;
} else if (availableDeviceTypes & AUDIO_DEVICE_IN_BUILTIN_MIC) {
device = AUDIO_DEVICE_IN_BUILTIN_MIC;
}
device = availableDevices.getFirstExistingDevice({
AUDIO_DEVICE_IN_WIRED_HEADSET, AUDIO_DEVICE_IN_USB_HEADSET,
AUDIO_DEVICE_IN_USB_DEVICE, AUDIO_DEVICE_IN_BUILTIN_MIC});
break;
case AUDIO_SOURCE_REMOTE_SUBMIX:
if (availableDeviceTypes & AUDIO_DEVICE_IN_REMOTE_SUBMIX) {
device = AUDIO_DEVICE_IN_REMOTE_SUBMIX;
}
device = availableDevices.getDevice(
AUDIO_DEVICE_IN_REMOTE_SUBMIX, String8(""), AUDIO_FORMAT_DEFAULT);
break;
case AUDIO_SOURCE_FM_TUNER:
if (availableDeviceTypes & AUDIO_DEVICE_IN_FM_TUNER) {
device = AUDIO_DEVICE_IN_FM_TUNER;
}
device = availableDevices.getDevice(
AUDIO_DEVICE_IN_FM_TUNER, String8(""), AUDIO_FORMAT_DEFAULT);
break;
case AUDIO_SOURCE_ECHO_REFERENCE:
if (availableDeviceTypes & AUDIO_DEVICE_IN_ECHO_REFERENCE) {
device = AUDIO_DEVICE_IN_ECHO_REFERENCE;
}
device = availableDevices.getDevice(
AUDIO_DEVICE_IN_ECHO_REFERENCE, String8(""), AUDIO_FORMAT_DEFAULT);
break;
default:
ALOGW("getDeviceForInputSource() invalid input source %d", inputSource);
break;
}
if (device == AUDIO_DEVICE_NONE) {
if (device == nullptr) {
ALOGV("getDeviceForInputSource() no device found for source %d", inputSource);
if (availableDeviceTypes & AUDIO_DEVICE_IN_STUB) {
device = AUDIO_DEVICE_IN_STUB;
}
ALOGE_IF(device == AUDIO_DEVICE_NONE,
device = availableDevices.getDevice(
AUDIO_DEVICE_IN_STUB, String8(""), AUDIO_FORMAT_DEFAULT);
ALOGE_IF(device == nullptr,
"getDeviceForInputSource() no default device defined");
}
ALOGV("getDeviceForInputSource()input source %d, device %08x", inputSource, device);
ALOGV_IF(device != nullptr,
"getDeviceForInputSource()input source %d, device %08x",
inputSource, device->type());
return device;
}
@ -684,11 +621,9 @@ DeviceVector Engine::getDevicesForProductStrategy(product_strategy_t strategy) c
auto legacyStrategy = mLegacyStrategyMap.find(strategy) != end(mLegacyStrategyMap) ?
mLegacyStrategyMap.at(strategy) : STRATEGY_NONE;
audio_devices_t devices = getDeviceForStrategyInt(legacyStrategy,
availableOutputDevices,
availableInputDevices, outputs,
(uint32_t)AUDIO_DEVICE_NONE);
return availableOutputDevices.getDevicesFromTypeMask(devices);
return getDevicesForStrategyInt(legacyStrategy,
availableOutputDevices,
availableInputDevices, outputs);
}
DeviceVector Engine::getOutputDevicesForAttributes(const audio_attributes_t &attributes,
@ -747,17 +682,21 @@ sp<DeviceDescriptor> Engine::getInputDeviceForAttributes(const audio_attributes_
if (device != nullptr) {
return device;
}
audio_devices_t deviceType = getDeviceForInputSource(attr.source);
if (audio_is_remote_submix_device(deviceType)) {
address = "0";
std::size_t pos;
std::string tags { attr.tags };
if ((pos = tags.find("addr=")) != std::string::npos) {
address = tags.substr(pos + std::strlen("addr="));
}
device = getDeviceForInputSource(attr.source);
if (device == nullptr || !audio_is_remote_submix_device(device->type())) {
// Return immediately if the device is null or it is not a remote submix device.
return device;
}
// For remote submix device, try to find the device by address.
address = "0";
std::size_t pos;
std::string tags { attr.tags };
if ((pos = tags.find("addr=")) != std::string::npos) {
address = tags.substr(pos + std::strlen("addr="));
}
return availableInputDevices.getDevice(deviceType,
return availableInputDevices.getDevice(device->type(),
String8(address.c_str()),
AUDIO_FORMAT_DEFAULT);
}

@ -73,15 +73,14 @@ private:
status_t setDefaultDevice(audio_devices_t device);
audio_devices_t getDeviceForStrategyInt(legacy_strategy strategy,
DeviceVector availableOutputDevices,
DeviceVector availableInputDevices,
const SwAudioOutputCollection &outputs,
uint32_t outputDeviceTypesToIgnore) const;
DeviceVector getDevicesForStrategyInt(legacy_strategy strategy,
DeviceVector availableOutputDevices,
DeviceVector availableInputDevices,
const SwAudioOutputCollection &outputs) const;
DeviceVector getDevicesForProductStrategy(product_strategy_t strategy) const;
audio_devices_t getDeviceForInputSource(audio_source_t inputSource) const;
sp<DeviceDescriptor> getDeviceForInputSource(audio_source_t inputSource) const;
DeviceStrategyMap mDevicesForStrategies;

@ -1206,9 +1206,9 @@ audio_io_handle_t AudioPolicyManager::getOutputForDevices(
if (!desc->isDuplicated() && (profile == desc->mProfile)) {
// reuse direct output if currently open by the same client
// and configured with same parameters
if ((config->sample_rate == desc->mSamplingRate) &&
(config->format == desc->mFormat) &&
(channelMask == desc->mChannelMask) &&
if ((config->sample_rate == desc->getSamplingRate()) &&
(config->format == desc->getFormat()) &&
(channelMask == desc->getChannelMask()) &&
(session == desc->mDirectClientSession)) {
desc->mDirectOpenCount++;
ALOGI("%s reusing direct output %d for session %d", __func__,
@ -1248,13 +1248,13 @@ audio_io_handle_t AudioPolicyManager::getOutputForDevices(
// only accept an output with the requested parameters
if (status != NO_ERROR ||
(config->sample_rate != 0 && config->sample_rate != outputDesc->mSamplingRate) ||
(config->format != AUDIO_FORMAT_DEFAULT && config->format != outputDesc->mFormat) ||
(channelMask != 0 && channelMask != outputDesc->mChannelMask)) {
(config->sample_rate != 0 && config->sample_rate != outputDesc->getSamplingRate()) ||
(config->format != AUDIO_FORMAT_DEFAULT && config->format != outputDesc->getFormat()) ||
(channelMask != 0 && channelMask != outputDesc->getChannelMask())) {
ALOGV("%s failed opening direct output: output %d sample rate %d %d,"
"format %d %d, channel mask %04x %04x", __func__, output, config->sample_rate,
outputDesc->mSamplingRate, config->format, outputDesc->mFormat,
channelMask, outputDesc->mChannelMask);
outputDesc->getSamplingRate(), config->format, outputDesc->getFormat(),
channelMask, outputDesc->getChannelMask());
if (output != AUDIO_IO_HANDLE_NONE) {
outputDesc->close();
}
@ -1525,13 +1525,13 @@ audio_io_handle_t AudioPolicyManager::selectOutput(const SortedVector<audio_io_h
// If haptic channel is specified, use the haptic output if present.
// When using haptic output, same audio format and sample rate are required.
const uint32_t outputHapticChannelCount = audio_channel_count_from_out_mask(
outputDesc->mChannelMask & AUDIO_CHANNEL_HAPTIC_ALL);
outputDesc->getChannelMask() & AUDIO_CHANNEL_HAPTIC_ALL);
if ((hapticChannelCount == 0) != (outputHapticChannelCount == 0)) {
continue;
}
if (outputHapticChannelCount >= hapticChannelCount
&& format == outputDesc->mFormat
&& samplingRate == outputDesc->mSamplingRate) {
&& format == outputDesc->getFormat()
&& samplingRate == outputDesc->getSamplingRate()) {
currentMatchCriteria[0] = outputHapticChannelCount;
}
@ -1539,12 +1539,13 @@ audio_io_handle_t AudioPolicyManager::selectOutput(const SortedVector<audio_io_h
currentMatchCriteria[1] = popcount(outputDesc->mFlags & functionalFlags);
// channel mask and channel count match
uint32_t outputChannelCount = audio_channel_count_from_out_mask(outputDesc->mChannelMask);
uint32_t outputChannelCount = audio_channel_count_from_out_mask(
outputDesc->getChannelMask());
if (channelMask != AUDIO_CHANNEL_NONE && channelCount > 2 &&
channelCount <= outputChannelCount) {
if ((audio_channel_mask_get_representation(channelMask) ==
audio_channel_mask_get_representation(outputDesc->mChannelMask)) &&
((channelMask & outputDesc->mChannelMask) == channelMask)) {
audio_channel_mask_get_representation(outputDesc->getChannelMask())) &&
((channelMask & outputDesc->getChannelMask()) == channelMask)) {
currentMatchCriteria[2] = outputChannelCount;
}
currentMatchCriteria[3] = outputChannelCount;
@ -1552,8 +1553,8 @@ audio_io_handle_t AudioPolicyManager::selectOutput(const SortedVector<audio_io_h
// sampling rate match
if (samplingRate > SAMPLE_RATE_HZ_DEFAULT &&
samplingRate <= outputDesc->mSamplingRate) {
currentMatchCriteria[4] = outputDesc->mSamplingRate;
samplingRate <= outputDesc->getSamplingRate()) {
currentMatchCriteria[4] = outputDesc->getSamplingRate();
}
// performance flags match
@ -1563,7 +1564,7 @@ audio_io_handle_t AudioPolicyManager::selectOutput(const SortedVector<audio_io_h
if (format != AUDIO_FORMAT_INVALID) {
currentMatchCriteria[6] =
AudioPort::kFormatDistanceMax -
AudioPort::formatDistance(format, outputDesc->mFormat);
AudioPort::formatDistance(format, outputDesc->getFormat());
}
// primary output match
@ -2922,9 +2923,9 @@ status_t AudioPolicyManager::registerPolicyMixes(const Vector<AudioMix>& mixes)
// stereo and let audio flinger do the channel conversion if needed.
outputConfig.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
inputConfig.channel_mask = AUDIO_CHANNEL_IN_STEREO;
rSubmixModule->addOutputProfile(address, &outputConfig,
rSubmixModule->addOutputProfile(address.c_str(), &outputConfig,
AUDIO_DEVICE_OUT_REMOTE_SUBMIX, address);
rSubmixModule->addInputProfile(address, &inputConfig,
rSubmixModule->addInputProfile(address.c_str(), &inputConfig,
AUDIO_DEVICE_IN_REMOTE_SUBMIX, address);
if ((res = setDeviceConnectionStateInt(deviceTypeToMakeAvailable,
@ -3020,8 +3021,8 @@ status_t AudioPolicyManager::unregisterPolicyMixes(Vector<AudioMix> mixes)
}
}
}
rSubmixModule->removeOutputProfile(address);
rSubmixModule->removeInputProfile(address);
rSubmixModule->removeOutputProfile(address.c_str());
rSubmixModule->removeInputProfile(address.c_str());
} else if ((mix.mRouteFlags & MIX_ROUTE_FLAG_RENDER) == MIX_ROUTE_FLAG_RENDER) {
if (mPolicyMixes.unregisterMix(mix) != NO_ERROR) {
@ -3233,7 +3234,7 @@ bool AudioPolicyManager::isDirectOutputSupported(const audio_config_base_t& conf
ALOGV("%s() profile %sfound with name: %s, "
"sample rate: %u, format: 0x%x, channel_mask: 0x%x, output flags: 0x%x",
__FUNCTION__, profile != 0 ? "" : "NOT ",
(profile != 0 ? profile->getTagName().string() : "null"),
(profile != 0 ? profile->getTagName().c_str() : "null"),
config.sample_rate, config.format, config.channel_mask, output_flags);
return (profile != 0);
}
@ -3897,7 +3898,7 @@ status_t AudioPolicyManager::connectAudioSource(const sp<SourceClientDescriptor>
if (srcDevice->hasSameHwModuleAs(sinkDevice) &&
srcDevice->getModuleVersionMajor() >= 3 &&
sinkDevice->getModule()->supportsPatch(srcDevice, sinkDevice) &&
srcDevice->getAudioPort()->mGains.size() > 0) {
srcDevice->getAudioPort()->getGains().size() > 0) {
ALOGV("%s Device to Device route supported by >=3.0 HAL", __FUNCTION__);
// TODO: may explicitly specify whether we should use HW or SW patch
// create patch between src device and output device
@ -4137,7 +4138,7 @@ status_t AudioPolicyManager::setSurroundFormatEnabled(audio_format_t audioFormat
for (size_t i = 0; i < hdmiOutputDevices.size(); i++) {
// Simulate reconnection to update enabled surround sound formats.
String8 address = hdmiOutputDevices[i]->address();
String8 name = hdmiOutputDevices[i]->getName();
std::string name = hdmiOutputDevices[i]->getName();
status_t status = setDeviceConnectionStateInt(AUDIO_DEVICE_OUT_HDMI,
AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
address.c_str(),
@ -4159,7 +4160,7 @@ status_t AudioPolicyManager::setSurroundFormatEnabled(audio_format_t audioFormat
for (size_t i = 0; i < hdmiInputDevices.size(); i++) {
// Simulate reconnection to update enabled surround sound formats.
String8 address = hdmiInputDevices[i]->address();
String8 name = hdmiInputDevices[i]->getName();
std::string name = hdmiInputDevices[i]->getName();
status_t status = setDeviceConnectionStateInt(AUDIO_DEVICE_IN_HDMI,
AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
address.c_str(),
@ -4642,7 +4643,7 @@ status_t AudioPolicyManager::checkOutputsForDevice(const sp<DeviceDescriptor>& d
}
ALOGV("opening output for device %08x with params %s profile %p name %s",
deviceType, address.string(), profile.get(), profile->getName().string());
deviceType, address.string(), profile.get(), profile->getName().c_str());
desc = new SwAudioOutputDescriptor(profile, mpClientInterface);
audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
status_t status = desc->open(nullptr, DeviceVector(device),

@ -38,7 +38,7 @@
#include <AudioPolicyConfig.h>
#include <AudioPort.h>
#include <AudioPatch.h>
#include <AudioProfile.h>
#include <AudioProfileVector.h>
#include <DeviceDescriptor.h>
#include <IOProfile.h>
#include <HwModule.h>

@ -396,12 +396,11 @@ void AudioPolicyManagerTestMsd::SetUpConfig(AudioPolicyConfig *config) {
mMsdOutputDevice->attach(msdModule);
mMsdInputDevice->attach(msdModule);
sp<OutputProfile> msdOutputProfile = new OutputProfile(String8("msd input"));
sp<OutputProfile> msdOutputProfile = new OutputProfile("msd input");
msdOutputProfile->addAudioProfile(pcmOutputProfile);
msdOutputProfile->addSupportedDevice(mMsdOutputDevice);
msdModule->addOutputProfile(msdOutputProfile);
sp<OutputProfile> msdCompressedOutputProfile =
new OutputProfile(String8("msd compressed input"));
sp<OutputProfile> msdCompressedOutputProfile = new OutputProfile("msd compressed input");
msdCompressedOutputProfile->addAudioProfile(ac3OutputProfile);
msdCompressedOutputProfile->setFlags(
AUDIO_OUTPUT_FLAG_DIRECT | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD |
@ -409,7 +408,7 @@ void AudioPolicyManagerTestMsd::SetUpConfig(AudioPolicyConfig *config) {
msdCompressedOutputProfile->addSupportedDevice(mMsdOutputDevice);
msdModule->addOutputProfile(msdCompressedOutputProfile);
sp<InputProfile> msdInputProfile = new InputProfile(String8("msd output"));
sp<InputProfile> msdInputProfile = new InputProfile("msd output");
msdInputProfile->addAudioProfile(pcmInputProfile);
msdInputProfile->addSupportedDevice(mMsdInputDevice);
msdModule->addInputProfile(msdInputProfile);
@ -419,7 +418,7 @@ void AudioPolicyManagerTestMsd::SetUpConfig(AudioPolicyConfig *config) {
sp<AudioProfile> dtsOutputProfile = new AudioProfile(
AUDIO_FORMAT_DTS, AUDIO_CHANNEL_OUT_5POINT1, 48000);
config->getDefaultOutputDevice()->addAudioProfile(dtsOutputProfile);
sp<OutputProfile> primaryEncodedOutputProfile = new OutputProfile(String8("encoded"));
sp<OutputProfile> primaryEncodedOutputProfile = new OutputProfile("encoded");
primaryEncodedOutputProfile->addAudioProfile(dtsOutputProfile);
primaryEncodedOutputProfile->setFlags(AUDIO_OUTPUT_FLAG_DIRECT);
primaryEncodedOutputProfile->addSupportedDevice(config->getDefaultOutputDevice());

Loading…
Cancel
Save