Merge "NuPlayerRenderer: delay video until audio clock is ready"
diff --git a/media/libmedia/AudioTrackShared.cpp b/media/libmedia/AudioTrackShared.cpp
index 666b747..9d5d996 100644
--- a/media/libmedia/AudioTrackShared.cpp
+++ b/media/libmedia/AudioTrackShared.cpp
@@ -240,6 +240,7 @@
errno = 0;
(void) syscall(__NR_futex, &cblk->mFutex,
mClientInServer ? FUTEX_WAIT_PRIVATE : FUTEX_WAIT, old & ~CBLK_FUTEX_WAKE, ts);
+ status_t error = errno; // clock_gettime can affect errno
// update total elapsed time spent waiting
if (measure) {
struct timespec after;
@@ -257,7 +258,7 @@
before = after;
beforeIsValid = true;
}
- switch (errno) {
+ switch (error) {
case 0: // normal wakeup by server, or by binderDied()
case EWOULDBLOCK: // benign race condition with server
case EINTR: // wait was interrupted by signal or other spurious wakeup
@@ -265,7 +266,7 @@
// FIXME these error/non-0 status are being dropped
break;
default:
- status = errno;
+ status = error;
ALOGE("%s unexpected error %s", __func__, strerror(status));
goto end;
}
diff --git a/media/libstagefright/CallbackDataSource.cpp b/media/libstagefright/CallbackDataSource.cpp
index e17fdf8..4c0a578 100644
--- a/media/libstagefright/CallbackDataSource.cpp
+++ b/media/libstagefright/CallbackDataSource.cpp
@@ -64,7 +64,7 @@
mIDataSource->readAt(offset + totalNumRead, numToRead);
// A negative return value represents an error. Pass it on.
if (numRead < 0) {
- return numRead;
+ return numRead == ERROR_END_OF_STREAM && totalNumRead > 0 ? totalNumRead : numRead;
}
// A zero return value signals EOS. Return the bytes read so far.
if (numRead == 0) {
diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp
index 5020c6c..163a527 100644
--- a/media/libstagefright/DataSource.cpp
+++ b/media/libstagefright/DataSource.cpp
@@ -48,6 +48,8 @@
#include <cutils/properties.h>
+#include <private/android_filesystem_config.h>
+
namespace android {
bool DataSource::getUInt16(off64_t offset, uint16_t *x) {
@@ -173,7 +175,10 @@
RegisterSniffer_l(SniffMP3);
RegisterSniffer_l(SniffAAC);
RegisterSniffer_l(SniffMPEG2PS);
- RegisterSniffer_l(SniffWVM);
+ if (getuid() == AID_MEDIA) {
+ // WVM only in the media server process
+ RegisterSniffer_l(SniffWVM);
+ }
RegisterSniffer_l(SniffMidi);
char value[PROPERTY_VALUE_MAX];
diff --git a/media/libstagefright/MediaExtractor.cpp b/media/libstagefright/MediaExtractor.cpp
index e1b0dd9..99e58f1 100644
--- a/media/libstagefright/MediaExtractor.cpp
+++ b/media/libstagefright/MediaExtractor.cpp
@@ -138,6 +138,17 @@
// remote extractor
ALOGV("get service manager");
sp<IBinder> binder = defaultServiceManager()->getService(String16("media.extractor"));
+
+ // Check if it's WVM, since WVMExtractor needs to be created in the media server process,
+ // not the extractor process.
+ String8 mime8;
+ float confidence;
+ sp<AMessage> meta;
+ if (SniffWVM(source, &mime8, &confidence, &meta) &&
+ !strcasecmp(mime8, MEDIA_MIMETYPE_CONTAINER_WVM)) {
+ return new WVMExtractor(source);
+ }
+
if (binder != 0) {
sp<IMediaExtractorService> mediaExService(interface_cast<IMediaExtractorService>(binder));
sp<IMediaExtractor> ex = mediaExService->makeExtractor(RemoteDataSource::wrap(source), mime);
@@ -213,7 +224,7 @@
ret = new MatroskaExtractor(source);
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2TS)) {
ret = new MPEG2TSExtractor(source);
- } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_WVM)) {
+ } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_WVM) && getuid() == AID_MEDIA) {
// Return now. WVExtractor should not have the DrmFlag set in the block below.
return new WVMExtractor(source);
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC_ADTS)) {
diff --git a/media/mtp/MtpDevice.cpp b/media/mtp/MtpDevice.cpp
index f8b913a..23e432e 100644
--- a/media/mtp/MtpDevice.cpp
+++ b/media/mtp/MtpDevice.cpp
@@ -659,6 +659,13 @@
return false;
}
+ // If object size 0 byte, the remote device can reply response packet
+ // without sending any data packets.
+ if (mData.getContainerType() == MTP_CONTAINER_TYPE_RESPONSE) {
+ mResponse.copyFrom(mData);
+ return mResponse.getResponseCode() == MTP_RESPONSE_OK;
+ }
+
const uint32_t fullLength = mData.getContainerLength();
if ((!expectedLength && fullLength < MTP_CONTAINER_HEADER_SIZE) ||
(expectedLength && *expectedLength + MTP_CONTAINER_HEADER_SIZE != fullLength)) {
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 462a676..780d772 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -185,8 +185,8 @@
mSystemReady(false)
{
getpid_cached = getpid();
- char value[PROPERTY_VALUE_MAX];
- bool doLog = (property_get("ro.test_harness", value, "0") > 0) && (atoi(value) == 1);
+ // disable media.log until the service is reenabled, see b/26306954
+ const bool doLog = false; // property_get_bool("ro.test_harness", false);
if (doLog) {
mLogMemoryDealer = new MemoryDealer(kLogMemorySize, "LogWriters",
MemoryHeapBase::READ_ONLY);
@@ -261,16 +261,17 @@
}
// Tell media.log service about any old writers that still need to be unregistered
- sp<IBinder> binder = defaultServiceManager()->getService(String16("media.log"));
- if (binder != 0) {
- sp<IMediaLogService> mediaLogService(interface_cast<IMediaLogService>(binder));
- for (size_t count = mUnregisteredWriters.size(); count > 0; count--) {
- sp<IMemory> iMemory(mUnregisteredWriters.top()->getIMemory());
- mUnregisteredWriters.pop();
- mediaLogService->unregisterWriter(iMemory);
+ if (mLogMemoryDealer != 0) {
+ sp<IBinder> binder = defaultServiceManager()->getService(String16("media.log"));
+ if (binder != 0) {
+ sp<IMediaLogService> mediaLogService(interface_cast<IMediaLogService>(binder));
+ for (size_t count = mUnregisteredWriters.size(); count > 0; count--) {
+ sp<IMemory> iMemory(mUnregisteredWriters.top()->getIMemory());
+ mUnregisteredWriters.pop();
+ mediaLogService->unregisterWriter(iMemory);
+ }
}
}
-
}
static const char * const audio_interfaces[] = {
diff --git a/services/audiopolicy/common/include/policy.h b/services/audiopolicy/common/include/policy.h
index 1a1cbb2..34984f9 100755
--- a/services/audiopolicy/common/include/policy.h
+++ b/services/audiopolicy/common/include/policy.h
@@ -18,9 +18,7 @@
#include <system/audio.h>
-static const uint32_t gDynamicRate = 0;
static const audio_format_t gDynamicFormat = AUDIO_FORMAT_DEFAULT;
-static const audio_channel_mask_t gDynamicChannelMask = AUDIO_CHANNEL_NONE;
// For mixed output and inputs, the policy will use max mixer sampling rates.
// Do not limit sampling rate otherwise
diff --git a/services/audiopolicy/common/managerdefinitions/Android.mk b/services/audiopolicy/common/managerdefinitions/Android.mk
index dc7eff7..dffeb7e 100644
--- a/services/audiopolicy/common/managerdefinitions/Android.mk
+++ b/services/audiopolicy/common/managerdefinitions/Android.mk
@@ -9,6 +9,7 @@
src/HwModule.cpp \
src/IOProfile.cpp \
src/AudioPort.cpp \
+ src/AudioProfile.cpp \
src/AudioPolicyMix.cpp \
src/AudioPatch.cpp \
src/AudioInputDescriptor.cpp \
@@ -18,7 +19,8 @@
src/SoundTriggerSession.cpp \
src/SessionRoute.cpp \
src/AudioSourceDescriptor.cpp \
- src/TypeConverter.cpp
+ src/TypeConverter.cpp \
+ src/AudioSession.cpp
LOCAL_SHARED_LIBRARIES := \
libcutils \
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
index 6d04811..7e5ef5d 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
@@ -17,6 +17,7 @@
#pragma once
#include "AudioPort.h"
+#include "AudioSession.h"
#include <utils/Errors.h>
#include <system/audio.h>
#include <utils/SortedVector.h>
@@ -36,7 +37,6 @@
void setIoHandle(audio_io_handle_t ioHandle);
audio_port_handle_t getId() const;
audio_module_handle_t getModuleHandle() const;
- void changeOpenRefCount(int delta);
uint32_t getOpenRefCount() const;
status_t dump(int fd);
@@ -45,13 +45,7 @@
audio_devices_t mDevice; // current device this input is routed to
AudioMix *mPolicyMix; // non NULL when used by a dynamic policy
audio_patch_handle_t mPatchHandle;
- uint32_t mRefCount; // number of AudioRecord clients active on
- // this input
- audio_source_t mInputSource; // input source selected by application
- //(mediarecorder.h)
const sp<IOProfile> mProfile; // I/O profile this output derives from
- SortedVector<audio_session_t> mSessions; // audio sessions attached to this input
- bool mIsSoundTrigger; // used by a soundtrigger capture
virtual void toAudioPortConfig(struct audio_port_config *dstConfig,
const struct audio_port_config *srcConfig = NULL) const;
@@ -61,10 +55,20 @@
SortedVector<audio_session_t> getPreemptedSessions() const;
bool hasPreemptedSession(audio_session_t session) const;
void clearPreemptedSessions();
+ bool isActive() const;
+ bool isSourceActive(audio_source_t source) const;
+ audio_source_t inputSource() const;
+ bool isSoundTrigger() const;
+ status_t addAudioSession(audio_session_t session,
+ const sp<AudioSession>& audioSession);
+ status_t removeAudioSession(audio_session_t session);
+ sp<AudioSession> getAudioSession(audio_session_t session) const;
+ AudioSessionCollection getActiveAudioSessions() const;
private:
audio_port_handle_t mId;
- uint32_t mOpenRefCount;
+ // audio sessions attached to this input
+ AudioSessionCollection mSessions;
// Because a preemtible capture session can preempt another one, we end up in an endless loop
// situation were each session is allowed to restart after being preempted,
// thus preempting the other one which restarts and so on.
@@ -72,7 +76,6 @@
// a particular input started and prevent preemption of this active input by this session.
// We also inherit sessions from the preempted input to avoid a 3 way preemption loop etc...
SortedVector<audio_session_t> mPreemptedSessions;
-
};
class AudioInputCollection :
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
index 5ff0396..20c0e36 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
@@ -99,9 +99,8 @@
sp<OutputProfile> outProfile;
outProfile = new OutputProfile(String8("primary"));
outProfile->attach(module);
- outProfile->mSamplingRates.add(44100);
- outProfile->mFormats.add(AUDIO_FORMAT_PCM_16_BIT);
- outProfile->mChannelMasks.add(AUDIO_CHANNEL_OUT_STEREO);
+ outProfile->addAudioProfile(
+ new AudioProfile(AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO, 44100));
outProfile->addSupportedDevice(mDefaultOutputDevices);
outProfile->setFlags(AUDIO_OUTPUT_FLAG_PRIMARY);
module->mOutputProfiles.add(outProfile);
@@ -109,9 +108,8 @@
sp<InputProfile> inProfile;
inProfile = new InputProfile(String8("primary"));
inProfile->attach(module);
- inProfile->mSamplingRates.add(8000);
- inProfile->mFormats.add(AUDIO_FORMAT_PCM_16_BIT);
- inProfile->mChannelMasks.add(AUDIO_CHANNEL_IN_MONO);
+ inProfile->addAudioProfile(
+ new AudioProfile(AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_MONO, 8000));
inProfile->addSupportedDevice(defaultInputDevice);
module->mInputProfiles.add(inProfile);
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPort.h b/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
index 5666920..9aaaddf 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
@@ -16,6 +16,7 @@
#pragma once
+#include "AudioProfile.h"
#include <utils/String8.h>
#include <utils/Vector.h>
#include <utils/RefBase.h>
@@ -57,42 +58,44 @@
virtual void toAudioPort(struct audio_port *port) const;
virtual void importAudioPort(const sp<AudioPort> port);
- void clearCapabilities();
+ void clearCapabilities() { mProfiles.clearProfiles(); }
- void setSupportedFormats(const Vector <audio_format_t> &formats);
- void setSupportedSamplingRates(const Vector <uint32_t> &sampleRates)
- {
- mSamplingRates = sampleRates;
- }
- void setSupportedChannelMasks(const Vector <audio_channel_mask_t> &channelMasks)
- {
- mChannelMasks = channelMasks;
- }
+ void addAudioProfile(const sp<AudioProfile> &profile) { mProfiles.add(profile); }
+
+ void setAudioProfiles(const AudioProfileVector &profiles) { mProfiles = profiles; }
+ AudioProfileVector &getAudioProfiles() { return mProfiles; }
+
+ bool hasValidAudioProfile() const { return mProfiles.hasValidProfile(); }
+
+ bool hasDynamicAudioProfile() const { return mProfiles.hasDynamicProfile(); }
// searches for an exact match
- status_t checkExactSamplingRate(uint32_t samplingRate) const;
- // searches for a compatible match, and returns the best match via updatedSamplingRate
- status_t checkCompatibleSamplingRate(uint32_t samplingRate,
- uint32_t *updatedSamplingRate) const;
- // searches for an exact match
- status_t checkExactChannelMask(audio_channel_mask_t channelMask) const;
- // searches for a compatible match, currently implemented for input channel masks only
- status_t checkCompatibleChannelMask(audio_channel_mask_t channelMask,
- audio_channel_mask_t *updatedChannelMask) const;
+ status_t checkExactAudioProfile(uint32_t samplingRate,
+ audio_channel_mask_t channelMask,
+ audio_format_t format) const
+ {
+ return mProfiles.checkExactProfile(samplingRate, channelMask, format);
+ }
- status_t checkExactFormat(audio_format_t format) const;
- // searches for a compatible match, currently implemented for input formats only
- status_t checkCompatibleFormat(audio_format_t format, audio_format_t *updatedFormat) const;
+ // searches for a compatible match, currently implemented for input
+ // parameters are input|output, returned value is the best match.
+ status_t checkCompatibleAudioProfile(uint32_t &samplingRate,
+ audio_channel_mask_t &channelMask,
+ audio_format_t &format) const
+ {
+ return mProfiles.checkCompatibleProfile(samplingRate, channelMask, format, mType, mRole);
+ }
+
+ void clearAudioProfiles() { return mProfiles.clearProfiles(); }
+
status_t checkGain(const struct audio_gain_config *gainConfig, int index) const;
- uint32_t pickSamplingRate() const;
- audio_channel_mask_t pickChannelMask() const;
- audio_format_t pickFormat() const;
+ void pickAudioProfile(uint32_t &samplingRate,
+ audio_channel_mask_t &channelMask,
+ audio_format_t &format) const;
static const audio_format_t sPcmFormatCompareTable[];
- static int compareFormats(const audio_format_t *format1, const audio_format_t *format2) {
- return compareFormats(*format1, *format2);
- }
+
static int compareFormats(audio_format_t format1, audio_format_t format2);
audio_module_handle_t getModuleHandle() const;
@@ -105,23 +108,27 @@
((mType == AUDIO_PORT_TYPE_MIX) && (mRole == AUDIO_PORT_ROLE_SINK));
}
- void dump(int fd, int spaces) const;
+ inline bool isDirectOutput() const
+ {
+ return (mType == AUDIO_PORT_TYPE_MIX) && (mRole == AUDIO_PORT_ROLE_SOURCE) &&
+ (mFlags & (AUDIO_OUTPUT_FLAG_DIRECT | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD));
+ }
+
+ void dump(int fd, int spaces, bool verbose = true) const;
void log(const char* indent) const;
- // by convention, "0' in the first entry in mSamplingRates, mChannelMasks or mFormats
- // indicates the supported parameters should be read from the output stream
- // after it is opened for the first time
- Vector <uint32_t> mSamplingRates; // supported sampling rates
- Vector <audio_channel_mask_t> mChannelMasks; // supported channel masks
- Vector <audio_format_t> mFormats; // supported audio formats
AudioGainCollection mGains; // gain controllers
sp<HwModule> mModule; // audio HW module exposing this I/O stream
private:
+ void pickChannelMask(audio_channel_mask_t &channelMask, const ChannelsVector &channelMasks) const;
+ void pickSamplingRate(uint32_t &rate,const SampleRateVector &samplingRates) const;
+
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)
static volatile int32_t mNextUniqueId;
};
@@ -132,9 +139,9 @@
virtual ~AudioPortConfig() {}
status_t applyAudioPortConfig(const struct audio_port_config *config,
- struct audio_port_config *backupConfig = NULL);
+ struct audio_port_config *backupConfig = NULL);
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 = 0;
virtual sp<AudioPort> getAudioPort() const = 0;
uint32_t mSamplingRate;
audio_format_t mFormat;
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioProfile.h b/services/audiopolicy/common/managerdefinitions/include/AudioProfile.h
new file mode 100644
index 0000000..9780dc6
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioProfile.h
@@ -0,0 +1,353 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "policy.h"
+#include <utils/String8.h>
+#include <utils/SortedVector.h>
+#include <utils/RefBase.h>
+#include <utils/Errors.h>
+#include <system/audio.h>
+#include <cutils/config_utils.h>
+
+namespace android {
+
+typedef SortedVector<uint32_t> SampleRateVector;
+typedef SortedVector<audio_channel_mask_t> ChannelsVector;
+typedef Vector<audio_format_t> FormatVector;
+
+template <typename T>
+bool operator == (const SortedVector<T> &left, const SortedVector<T> &right);
+
+class AudioProfile : public virtual RefBase
+{
+public:
+ AudioProfile(audio_format_t format,
+ audio_channel_mask_t channelMasks,
+ uint32_t samplingRate) :
+ mName(String8("")),
+ mFormat(format)
+ {
+ mChannelMasks.add(channelMasks);
+ mSamplingRates.add(samplingRate);
+ }
+
+ AudioProfile(audio_format_t format,
+ const ChannelsVector &channelMasks,
+ const SampleRateVector &samplingRateCollection) :
+ mName(String8("")),
+ mFormat(format),
+ mChannelMasks(channelMasks),
+ mSamplingRates(samplingRateCollection)
+ {}
+
+ audio_format_t getFormat() const { return mFormat; }
+
+ void setChannels(const ChannelsVector &channelMasks)
+ {
+ if (mIsDynamicChannels) {
+ mChannelMasks = channelMasks;
+ }
+ }
+ const ChannelsVector &getChannels() const { return mChannelMasks; }
+
+ void setSampleRates(const SampleRateVector &sampleRates)
+ {
+ if (mIsDynamicRate) {
+ mSamplingRates = sampleRates;
+ }
+ }
+ const SampleRateVector &getSampleRates() const { return mSamplingRates; }
+
+ bool isValid() const { return hasValidFormat() && hasValidRates() && hasValidChannels(); }
+
+ void clear()
+ {
+ if (mIsDynamicChannels) {
+ mChannelMasks.clear();
+ }
+ if (mIsDynamicRate) {
+ mSamplingRates.clear();
+ }
+ }
+
+ inline bool supportsChannels(audio_channel_mask_t channels) const
+ {
+ return mChannelMasks.indexOf(channels) >= 0;
+ }
+ inline bool supportsRate(uint32_t rate) const
+ {
+ return mSamplingRates.indexOf(rate) >= 0;
+ }
+
+ status_t checkExact(uint32_t rate, audio_channel_mask_t channels, audio_format_t format) const;
+
+ status_t checkCompatibleChannelMask(audio_channel_mask_t channelMask,
+ audio_channel_mask_t &updatedChannelMask,
+ audio_port_type_t portType,
+ audio_port_role_t portRole) const;
+
+ status_t checkCompatibleSamplingRate(uint32_t samplingRate,
+ uint32_t &updatedSamplingRate) const;
+
+ bool hasValidFormat() const { return mFormat != AUDIO_FORMAT_DEFAULT; }
+ bool hasValidRates() const { return !mSamplingRates.isEmpty(); }
+ bool hasValidChannels() const { return !mChannelMasks.isEmpty(); }
+
+ void setDynamicChannels(bool dynamic) { mIsDynamicChannels = dynamic; }
+ bool isDynamicChannels() const { return mIsDynamicChannels; }
+
+ void setDynamicRate(bool dynamic) { mIsDynamicRate = dynamic; }
+ bool isDynamicRate() const { return mIsDynamicRate; }
+
+ void setDynamicFormat(bool dynamic) { mIsDynamicFormat = dynamic; }
+ bool isDynamicFormat() const { return mIsDynamicFormat; }
+
+ bool isDynamic() { return mIsDynamicFormat || mIsDynamicChannels || mIsDynamicRate; }
+
+ void dump(int fd, int spaces) const;
+
+private:
+ String8 mName;
+ audio_format_t mFormat;
+ ChannelsVector mChannelMasks;
+ SampleRateVector mSamplingRates;
+
+ bool mIsDynamicFormat = false;
+ bool mIsDynamicChannels = false;
+ bool mIsDynamicRate = false;
+};
+
+
+class AudioProfileVector : public Vector<sp<AudioProfile> >
+{
+public:
+ ssize_t add(const sp<AudioProfile> &profile)
+ {
+ ssize_t index = Vector::add(profile);
+ // we sort from worst to best, so that AUDIO_FORMAT_DEFAULT is always the first entry.
+ // TODO: compareFormats could be a lambda to convert between pointer-to-format to format:
+ // [](const audio_format_t *format1, const audio_format_t *format2) {
+ // return compareFormats(*format1, *format2);
+ // }
+ sort(compareFormats);
+ return index;
+ }
+
+ // This API is intended to be used by the policy manager once retrieving capabilities
+ // for a profile with dynamic format, rate and channels attributes
+ ssize_t addProfileFromHal(const sp<AudioProfile> &profileToAdd)
+ {
+ // Check valid profile to add:
+ if (!profileToAdd->hasValidFormat()) {
+ return -1;
+ }
+ if (!profileToAdd->hasValidChannels() && !profileToAdd->hasValidRates()) {
+ FormatVector formats;
+ formats.add(profileToAdd->getFormat());
+ setFormats(FormatVector(formats));
+ return 0;
+ }
+ if (!profileToAdd->hasValidChannels() && profileToAdd->hasValidRates()) {
+ setSampleRatesFor(profileToAdd->getSampleRates(), profileToAdd->getFormat());
+ return 0;
+ }
+ if (profileToAdd->hasValidChannels() && !profileToAdd->hasValidRates()) {
+ setChannelsFor(profileToAdd->getChannels(), profileToAdd->getFormat());
+ return 0;
+ }
+ // Go through the list of profile to avoid duplicates
+ for (size_t profileIndex = 0; profileIndex < size(); profileIndex++) {
+ const sp<AudioProfile> &profile = itemAt(profileIndex);
+ if (profile->isValid() && profile == profileToAdd) {
+ // Nothing to do
+ return profileIndex;
+ }
+ }
+ profileToAdd->setDynamicFormat(true); // set the format as dynamic to allow removal
+ return add(profileToAdd);
+ }
+
+ sp<AudioProfile> getFirstValidProfile() const
+ {
+ for (size_t i = 0; i < size(); i++) {
+ if (itemAt(i)->isValid()) {
+ return itemAt(i);
+ }
+ }
+ return 0;
+ }
+
+ bool hasValidProfile() const { return getFirstValidProfile() != 0; }
+
+ status_t checkExactProfile(uint32_t samplingRate, audio_channel_mask_t channelMask,
+ audio_format_t format) const;
+
+ status_t checkCompatibleProfile(uint32_t &samplingRate, audio_channel_mask_t &channelMask,
+ audio_format_t &format,
+ audio_port_type_t portType,
+ audio_port_role_t portRole) const;
+
+ FormatVector getSupportedFormats() const
+ {
+ FormatVector supportedFormats;
+ for (size_t i = 0; i < size(); i++) {
+ if (itemAt(i)->hasValidFormat()) {
+ supportedFormats.add(itemAt(i)->getFormat());
+ }
+ }
+ return supportedFormats;
+ }
+
+ bool hasDynamicProfile() const
+ {
+ for (size_t i = 0; i < size(); i++) {
+ if (itemAt(i)->isDynamic()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool hasDynamicFormat() const
+ {
+ return getProfileFor(gDynamicFormat) != 0;
+ }
+
+ bool hasDynamicChannelsFor(audio_format_t format) const
+ {
+ for (size_t i = 0; i < size(); i++) {
+ sp<AudioProfile> profile = itemAt(i);
+ if (profile->getFormat() == format && profile->isDynamicChannels()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool hasDynamicRateFor(audio_format_t format) const
+ {
+ for (size_t i = 0; i < size(); i++) {
+ sp<AudioProfile> profile = itemAt(i);
+ if (profile->getFormat() == format && profile->isDynamicRate()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // One audio profile will be added for each format supported by Audio HAL
+ void setFormats(const FormatVector &formats)
+ {
+ // Only allow to change the format of dynamic profile
+ sp<AudioProfile> dynamicFormatProfile = getProfileFor(gDynamicFormat);
+ if (dynamicFormatProfile == 0) {
+ return;
+ }
+ clearProfiles();
+ for (size_t i = 0; i < formats.size(); i++) {
+ sp<AudioProfile> profile = new AudioProfile(formats[i],
+ dynamicFormatProfile->getChannels(),
+ dynamicFormatProfile->getSampleRates());
+ profile->setDynamicFormat(true);
+ profile->setDynamicChannels(dynamicFormatProfile->isDynamicChannels());
+ profile->setDynamicRate(dynamicFormatProfile->isDynamicRate());
+ add(profile);
+ }
+ }
+
+ void setSampleRatesFor(const SampleRateVector &sampleRates, audio_format_t format)
+ {
+ for (size_t i = 0; i < size(); i++) {
+ sp<AudioProfile> profile = itemAt(i);
+ if (profile->getFormat() == format && profile->isDynamicRate()) {
+ if (profile->hasValidRates()) {
+ // Need to create a new profile with same format
+ sp<AudioProfile> profileToAdd = new AudioProfile(format, profile->getChannels(),
+ sampleRates);
+ profileToAdd->setDynamicFormat(true); // need to set to allow cleaning
+ add(profileToAdd);
+ } else {
+ profile->setSampleRates(sampleRates);
+ }
+ return;
+ }
+ }
+ }
+
+ void setChannelsFor(const ChannelsVector &channelMasks, audio_format_t format)
+ {
+ for (size_t i = 0; i < size(); i++) {
+ sp<AudioProfile> profile = itemAt(i);
+ if (profile->getFormat() == format && profile->isDynamicChannels()) {
+ if (profile->hasValidChannels()) {
+ // Need to create a new profile with same format
+ sp<AudioProfile> profileToAdd = new AudioProfile(format, channelMasks,
+ profile->getSampleRates());
+ profileToAdd->setDynamicFormat(true); // need to set to allow cleaning
+ add(profileToAdd);
+ } else {
+ profile->setChannels(channelMasks);
+ }
+ return;
+ }
+ }
+ }
+
+ void clearProfiles()
+ {
+ for (size_t i = size(); i != 0; ) {
+ sp<AudioProfile> profile = itemAt(--i);
+ if (profile->isDynamicFormat() && profile->hasValidFormat()) {
+ removeAt(i);
+ continue;
+ }
+ profile->clear();
+ }
+ }
+
+ void dump(int fd, int spaces) const
+ {
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+
+ snprintf(buffer, SIZE, "%*s- Profiles:\n", spaces, "");
+ write(fd, buffer, strlen(buffer));
+ for (size_t i = 0; i < size(); i++) {
+ snprintf(buffer, SIZE, "%*sProfile %zu:", spaces + 4, "", i);
+ write(fd, buffer, strlen(buffer));
+ itemAt(i)->dump(fd, spaces + 8);
+ }
+ }
+
+private:
+ sp<AudioProfile> getProfileFor(audio_format_t format) const
+ {
+ for (size_t i = 0; i < size(); i++) {
+ if (itemAt(i)->getFormat() == format) {
+ return itemAt(i);
+ }
+ }
+ return 0;
+ }
+
+ static int compareFormats(const sp<AudioProfile> *profile1, const sp<AudioProfile> *profile2);
+};
+
+bool operator == (const AudioProfile &left, const AudioProfile &right);
+
+}; // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioSession.h b/services/audiopolicy/common/managerdefinitions/include/AudioSession.h
new file mode 100644
index 0000000..6feef80
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioSession.h
@@ -0,0 +1,87 @@
+/*
+ * 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 <system/audio.h>
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+#include <utils/Errors.h>
+#include <utils/KeyedVector.h>
+
+namespace android {
+
+class AudioSession : public RefBase
+{
+public:
+ AudioSession(audio_session_t session,
+ audio_source_t inputSource,
+ audio_format_t format,
+ uint32_t sampleRate,
+ audio_channel_mask_t channelMask,
+ audio_input_flags_t flags,
+ uid_t uid,
+ bool isSoundTrigger);
+
+ status_t dump(int fd, int spaces, int index) const;
+
+ audio_session_t session() const { return mSession; }
+ audio_source_t inputSource()const { return mInputSource; }
+ audio_format_t format() const { return mFormat; }
+ uint32_t sampleRate() const { return mSampleRate; }
+ audio_channel_mask_t channelMask() const { return mChannelMask; }
+ audio_input_flags_t flags() const { return mFlags; }
+ uid_t uid() const { return mUid; }
+ bool matches(const sp<AudioSession> &other) const;
+ bool isSoundTrigger() const { return mIsSoundTrigger; }
+ uint32_t openCount() const { return mOpenCount; } ;
+ uint32_t activeCount() const { return mActiveCount; } ;
+
+ uint32_t changeOpenCount(int delta);
+ uint32_t changeActiveCount(int delta);
+
+private:
+ const audio_session_t mSession;
+ const audio_source_t mInputSource;
+ const audio_format_t mFormat;
+ const uint32_t mSampleRate;
+ const audio_channel_mask_t mChannelMask;
+ const audio_input_flags_t mFlags;
+ const uid_t mUid;
+ bool mIsSoundTrigger;
+ uint32_t mOpenCount;
+ uint32_t mActiveCount;
+};
+
+class AudioSessionCollection :
+ public DefaultKeyedVector<audio_session_t, sp<AudioSession> >
+{
+public:
+ status_t addSession(audio_session_t session,
+ const sp<AudioSession>& audioSession);
+
+ status_t removeSession(audio_session_t session);
+
+ uint32_t getOpenCount() const;
+
+ AudioSessionCollection getActiveSessions() const;
+ bool hasActiveSession() const;
+ bool isSourceActive(audio_source_t source) const;
+
+ status_t dump(int fd, int spaces) const;
+};
+
+}; // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/ConfigParsingUtils.h b/services/audiopolicy/common/managerdefinitions/include/ConfigParsingUtils.h
index 1eddab9..ab23105 100644
--- a/services/audiopolicy/common/managerdefinitions/include/ConfigParsingUtils.h
+++ b/services/audiopolicy/common/managerdefinitions/include/ConfigParsingUtils.h
@@ -45,8 +45,7 @@
static void loadAudioPortGains(cnode *root, AudioPort &audioPort);
static void loadDeviceDescriptorGains(cnode *root, sp<DeviceDescriptor> &deviceDesc);
static status_t loadHwModuleDevice(cnode *root, DeviceVector &devices);
- static status_t loadHwModuleInput(cnode *root, sp<HwModule> &module);
- static status_t loadHwModuleOutput(cnode *root, sp<HwModule> &module);
+ static status_t loadHwModuleProfile(cnode *root, sp<HwModule> &module, audio_port_role_t role);
static void loadDevicesFromTag(const char *tag, DeviceVector &devices,
const DeviceVector &declaredDevices);
static void loadHwModules(cnode *root, HwModuleCollection &hwModules,
diff --git a/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
index 3f43963..8ece51b 100644
--- a/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
@@ -50,7 +50,7 @@
virtual void importAudioPort(const sp<AudioPort> port);
audio_port_handle_t getId() const;
- status_t dump(int fd, int spaces, int index) const;
+ status_t dump(int fd, int spaces, int index, bool verbose = true) const;
void log() const;
String8 mAddress;
@@ -85,7 +85,7 @@
audio_policy_dev_state_t getDeviceConnectionState(const sp<DeviceDescriptor> &devDesc) const;
- status_t dump(int fd, const String8 &direction) const;
+ status_t dump(int fd, const String8 &tag, int spaces = 0, bool verbose = true) const;
private:
void refreshTypes();
diff --git a/services/audiopolicy/common/managerdefinitions/include/TypeConverter.h b/services/audiopolicy/common/managerdefinitions/include/TypeConverter.h
index 9b96770..14e2ecc 100644
--- a/services/audiopolicy/common/managerdefinitions/include/TypeConverter.h
+++ b/services/audiopolicy/common/managerdefinitions/include/TypeConverter.h
@@ -27,14 +27,10 @@
namespace android {
-#define DYNAMIC_VALUE_TAG "dynamic" // special value for "channel_masks", "sampling_rates" and
- // "formats" in outputs descriptors indicating that supported
- // values should be queried after opening the output.
-
struct SampleRateTraits
{
typedef uint32_t Type;
- typedef Vector<Type> Collection;
+ typedef SortedVector<Type> Collection;
};
struct DeviceTraits
{
@@ -59,7 +55,7 @@
struct ChannelTraits
{
typedef audio_channel_mask_t Type;
- typedef Vector<Type> Collection;
+ typedef SortedVector<Type> Collection;
};
struct OutputChannelTraits : public ChannelTraits {};
struct InputChannelTraits : public ChannelTraits {};
@@ -139,50 +135,27 @@
const char *del = "|")
{
SampleRateTraits::Collection samplingRateCollection;
- // by convention, "0' in the first entry in mSamplingRates indicates the supported sampling
- // rates should be read from the output stream after it is opened for the first time
- if (samplingRates == DYNAMIC_VALUE_TAG) {
- samplingRateCollection.add(gDynamicRate);
- } else {
- collectionFromString<SampleRateTraits>(samplingRates, samplingRateCollection, del);
- }
+ collectionFromString<SampleRateTraits>(samplingRates, samplingRateCollection, del);
return samplingRateCollection;
}
static FormatTraits::Collection formatsFromString(const std::string &formats, const char *del = "|")
{
FormatTraits::Collection formatCollection;
- // by convention, "0' in the first entry in mFormats indicates the supported formats
- // should be read from the output stream after it is opened for the first time
- if (formats == DYNAMIC_VALUE_TAG) {
- formatCollection.add(gDynamicFormat);
- } else {
- FormatConverter::collectionFromString(formats, formatCollection, del);
- }
+ FormatConverter::collectionFromString(formats, formatCollection, del);
return formatCollection;
}
static audio_format_t formatFromString(const std::string &literalFormat)
{
audio_format_t format;
- // by convention, "0' in the first entry in literalFormat indicates the supported formats
- // should be read from the output stream after it is opened for the first time
- if (literalFormat == DYNAMIC_VALUE_TAG) {
- return gDynamicFormat;
- } else {
- FormatConverter::fromString(literalFormat, format);
- }
+ FormatConverter::fromString(literalFormat, format);
return format;
}
static audio_channel_mask_t channelMaskFromString(const std::string &literalChannels)
{
audio_channel_mask_t channels;
- // by convention, "0' in the first entry in literalChannels indicates the supported channels
- // should be read from the output stream after it is opened for the first time
- if (literalChannels == DYNAMIC_VALUE_TAG) {
- return gDynamicChannelMask;
- }
if (!OutputChannelConverter::fromString(literalChannels, channels) ||
!InputChannelConverter::fromString(literalChannels, channels)) {
return AUDIO_CHANNEL_INVALID;
@@ -194,13 +167,9 @@
const char *del = "|")
{
ChannelTraits::Collection channelMaskCollection;
- if (channels == DYNAMIC_VALUE_TAG) {
- channelMaskCollection.add(gDynamicChannelMask);
- } else {
- OutputChannelConverter::collectionFromString(channels, channelMaskCollection, del);
- InputChannelConverter::collectionFromString(channels, channelMaskCollection, del);
- ChannelIndexConverter::collectionFromString(channels, channelMaskCollection, del);
- }
+ OutputChannelConverter::collectionFromString(channels, channelMaskCollection, del);
+ InputChannelConverter::collectionFromString(channels, channelMaskCollection, del);
+ ChannelIndexConverter::collectionFromString(channels, channelMaskCollection, del);
return channelMaskCollection;
}
@@ -208,12 +177,8 @@
const char *del = "|")
{
InputChannelTraits::Collection inputChannelMaskCollection;
- if (inChannels == DYNAMIC_VALUE_TAG) {
- inputChannelMaskCollection.add(gDynamicChannelMask);
- } else {
- InputChannelConverter::collectionFromString(inChannels, inputChannelMaskCollection, del);
- ChannelIndexConverter::collectionFromString(inChannels, inputChannelMaskCollection, del);
- }
+ InputChannelConverter::collectionFromString(inChannels, inputChannelMaskCollection, del);
+ ChannelIndexConverter::collectionFromString(inChannels, inputChannelMaskCollection, del);
return inputChannelMaskCollection;
}
@@ -221,14 +186,8 @@
const char *del = "|")
{
OutputChannelTraits::Collection outputChannelMaskCollection;
- // by convention, "0' in the first entry in mChannelMasks indicates the supported channel
- // masks should be read from the output stream after it is opened for the first time
- if (outChannels == DYNAMIC_VALUE_TAG) {
- outputChannelMaskCollection.add(gDynamicChannelMask);
- } else {
- OutputChannelConverter::collectionFromString(outChannels, outputChannelMaskCollection, del);
- ChannelIndexConverter::collectionFromString(outChannels, outputChannelMaskCollection, del);
- }
+ OutputChannelConverter::collectionFromString(outChannels, outputChannelMaskCollection, del);
+ ChannelIndexConverter::collectionFromString(outChannels, outputChannelMaskCollection, del);
return outputChannelMaskCollection;
}
diff --git a/services/audiopolicy/common/managerdefinitions/include/audio_policy_conf.h b/services/audiopolicy/common/managerdefinitions/include/audio_policy_conf.h
index aac9e4d..0a27947 100644
--- a/services/audiopolicy/common/managerdefinitions/include/audio_policy_conf.h
+++ b/services/audiopolicy/common/managerdefinitions/include/audio_policy_conf.h
@@ -65,3 +65,7 @@
#define GAIN_STEP_VALUE "step_value_mB"
#define GAIN_MIN_RAMP_MS "min_ramp_ms"
#define GAIN_MAX_RAMP_MS "max_ramp_ms"
+
+#define DYNAMIC_VALUE_TAG "dynamic" // special value for "channel_masks", "sampling_rates" and
+ // "formats" in outputs descriptors indicating that supported
+ // values should be queried after opening the output.
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
index e828cc0..9b6469c 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
@@ -28,14 +28,11 @@
AudioInputDescriptor::AudioInputDescriptor(const sp<IOProfile>& profile)
: mIoHandle(0),
- mDevice(AUDIO_DEVICE_NONE), mPolicyMix(NULL), mPatchHandle(0), mRefCount(0),
- mInputSource(AUDIO_SOURCE_DEFAULT), mProfile(profile), mIsSoundTrigger(false), mId(0),
- mOpenRefCount(0)
+ mDevice(AUDIO_DEVICE_NONE), mPolicyMix(NULL), mPatchHandle(0),
+ mProfile(profile), mId(0)
{
if (profile != NULL) {
- mSamplingRate = profile->pickSamplingRate();
- mFormat = profile->pickFormat();
- mChannelMask = profile->pickChannelMask();
+ profile->pickAudioProfile(mSamplingRate, mChannelMask, mFormat);
if (profile->mGains.size() > 0) {
profile->mGains[0]->getDefaultConfig(&mGain);
}
@@ -56,20 +53,9 @@
return mProfile->getModuleHandle();
}
-void AudioInputDescriptor::changeOpenRefCount(int delta)
-{
- if ((delta + (int)mOpenRefCount) < 0) {
- ALOGW("changeOpenRefCount() invalid delta %d, refCount %d", delta, mOpenRefCount);
- mOpenRefCount = 0;
- return;
- }
- mOpenRefCount += delta;
- ALOGV("changeOpenRefCount() count %d", mOpenRefCount);
-}
-
uint32_t AudioInputDescriptor::getOpenRefCount() const
{
- return mOpenRefCount;
+ return mSessions.getOpenCount();
}
audio_port_handle_t AudioInputDescriptor::getId() const
@@ -77,6 +63,13 @@
return mId;
}
+audio_source_t AudioInputDescriptor::inputSource() const
+{
+ // TODO: return highest priority input source
+ return mSessions.size() > 0 ? mSessions.valueAt(0)->inputSource() :
+ AUDIO_SOURCE_DEFAULT;
+}
+
void AudioInputDescriptor::toAudioPortConfig(struct audio_port_config *dstConfig,
const struct audio_port_config *srcConfig) const
{
@@ -95,7 +88,7 @@
dstConfig->type = AUDIO_PORT_TYPE_MIX;
dstConfig->ext.mix.hw_module = getModuleHandle();
dstConfig->ext.mix.handle = mIoHandle;
- dstConfig->ext.mix.usecase.source = mInputSource;
+ dstConfig->ext.mix.usecase.source = inputSource();
}
void AudioInputDescriptor::toAudioPort(struct audio_port *port) const
@@ -130,6 +123,40 @@
mPreemptedSessions.clear();
}
+bool AudioInputDescriptor::isActive() const {
+ return mSessions.hasActiveSession();
+}
+
+bool AudioInputDescriptor::isSourceActive(audio_source_t source) const
+{
+ return mSessions.isSourceActive(source);
+}
+
+bool AudioInputDescriptor::isSoundTrigger() const {
+ // sound trigger and non sound trigger sessions are not mixed
+ // on a given input
+ return mSessions.valueAt(0)->isSoundTrigger();
+}
+
+sp<AudioSession> AudioInputDescriptor::getAudioSession(
+ audio_session_t session) const {
+ return mSessions.valueFor(session);
+}
+
+AudioSessionCollection AudioInputDescriptor::getActiveAudioSessions() const
+{
+ return mSessions.getActiveSessions();
+}
+
+status_t AudioInputDescriptor::addAudioSession(audio_session_t session,
+ const sp<AudioSession>& audioSession) {
+ return mSessions.addSession(session, audioSession);
+}
+
+status_t AudioInputDescriptor::removeAudioSession(audio_session_t session) {
+ return mSessions.removeSession(session);
+}
+
status_t AudioInputDescriptor::dump(int fd)
{
const size_t SIZE = 256;
@@ -146,13 +173,11 @@
result.append(buffer);
snprintf(buffer, SIZE, " Devices %08x\n", mDevice);
result.append(buffer);
- snprintf(buffer, SIZE, " Ref Count %d\n", mRefCount);
- result.append(buffer);
- snprintf(buffer, SIZE, " Open Ref Count %d\n", mOpenRefCount);
- result.append(buffer);
write(fd, result.string(), result.size());
+ mSessions.dump(fd, 1);
+
return NO_ERROR;
}
@@ -160,10 +185,7 @@
{
for (size_t i = 0; i < size(); i++) {
const sp<AudioInputDescriptor> inputDescriptor = valueAt(i);
- if (inputDescriptor->mRefCount == 0) {
- continue;
- }
- if (inputDescriptor->mInputSource == (int)source) {
+ if (inputDescriptor->isSourceActive(source)) {
return true;
}
}
@@ -186,8 +208,8 @@
{
uint32_t count = 0;
for (size_t i = 0; i < size(); i++) {
- const sp<AudioInputDescriptor> desc = valueAt(i);
- if (desc->mRefCount > 0) {
+ const sp<AudioInputDescriptor> inputDescriptor = valueAt(i);
+ if (inputDescriptor->isActive()) {
count++;
}
}
@@ -197,9 +219,10 @@
audio_io_handle_t AudioInputCollection::getActiveInput(bool ignoreVirtualInputs)
{
for (size_t i = 0; i < size(); i++) {
- const sp<AudioInputDescriptor> input_descriptor = valueAt(i);
- if ((input_descriptor->mRefCount > 0)
- && (!ignoreVirtualInputs || !is_virtual_input_device(input_descriptor->mDevice))) {
+ const sp<AudioInputDescriptor> inputDescriptor = valueAt(i);
+ if ((inputDescriptor->isActive())
+ && (!ignoreVirtualInputs ||
+ !is_virtual_input_device(inputDescriptor->mDevice))) {
return keyAt(i);
}
}
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
index 223fe80..5d0f03f 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
@@ -47,9 +47,7 @@
mStrategyMutedByDevice[i] = false;
}
if (port != NULL) {
- mSamplingRate = port->pickSamplingRate();
- mFormat = port->pickFormat();
- mChannelMask = port->pickChannelMask();
+ port->pickAudioProfile(mSamplingRate, mChannelMask, mFormat);
if (port->mGains.size() > 0) {
port->mGains[0]->getDefaultConfig(&mGain);
}
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
index 1713095..cde0923 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
@@ -16,7 +16,6 @@
#define LOG_TAG "APM::AudioPort"
//#define LOG_NDEBUG 0
-#include <media/AudioResamplerPublic.h>
#include "TypeConverter.h"
#include "AudioPort.h"
#include "HwModule.h"
@@ -68,420 +67,165 @@
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.
+ SortedVector<audio_format_t> flatenedFormats;
+ SampleRateVector flatenedRates;
+ ChannelsVector flatenedChannels;
+ for (size_t profileIndex = 0; profileIndex < mProfiles.size(); profileIndex++) {
+ if (mProfiles[profileIndex]->isValid()) {
+ audio_format_t formatToExport = mProfiles[profileIndex]->getFormat();
+ const SampleRateVector &ratesToExport = mProfiles[profileIndex]->getSampleRates();
+ const ChannelsVector &channelsToExport = mProfiles[profileIndex]->getChannels();
+
+ if (flatenedFormats.indexOf(formatToExport) < 0) {
+ flatenedFormats.add(formatToExport);
+ }
+ for (size_t rateIndex = 0; rateIndex < ratesToExport.size(); rateIndex++) {
+ uint32_t rate = ratesToExport[rateIndex];
+ if (flatenedRates.indexOf(rate) < 0) {
+ flatenedRates.add(rate);
+ }
+ }
+ for (size_t chanIndex = 0; chanIndex < channelsToExport.size(); chanIndex++) {
+ audio_channel_mask_t channels = channelsToExport[chanIndex];
+ if (flatenedChannels.indexOf(channels) < 0) {
+ flatenedChannels.add(channels);
+ }
+ }
+ 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);
- unsigned int i;
- for (i = 0; i < mSamplingRates.size() && i < AUDIO_PORT_MAX_SAMPLING_RATES; i++) {
- if (mSamplingRates[i] != 0) {
- port->sample_rates[i] = mSamplingRates[i];
- }
+ port->num_sample_rates = flatenedRates.size();
+ port->num_channel_masks = flatenedChannels.size();
+ port->num_formats = flatenedFormats.size();
+ for (size_t i = 0; i < flatenedRates.size(); i++) {
+ port->sample_rates[i] = flatenedRates[i];
}
- port->num_sample_rates = i;
- for (i = 0; i < mChannelMasks.size() && i < AUDIO_PORT_MAX_CHANNEL_MASKS; i++) {
- if (mChannelMasks[i] != 0) {
- port->channel_masks[i] = mChannelMasks[i];
- }
+ for (size_t i = 0; i < flatenedChannels.size(); i++) {
+ port->channel_masks[i] = flatenedChannels[i];
}
- port->num_channel_masks = i;
- for (i = 0; i < mFormats.size() && i < AUDIO_PORT_MAX_FORMATS; i++) {
- if (mFormats[i] != 0) {
- port->formats[i] = mFormats[i];
- }
+ for (size_t i = 0; i < flatenedFormats.size(); i++) {
+ port->formats[i] = flatenedFormats[i];
}
- port->num_formats = i;
ALOGV("AudioPort::toAudioPort() num gains %zu", mGains.size());
+ uint32_t i;
for (i = 0; i < mGains.size() && i < AUDIO_PORT_MAX_GAINS; i++) {
port->gains[i] = mGains[i]->getGain();
}
port->num_gains = i;
}
-void AudioPort::importAudioPort(const sp<AudioPort> port) {
- for (size_t k = 0 ; k < port->mSamplingRates.size() ; k++) {
- const uint32_t rate = port->mSamplingRates.itemAt(k);
- if (rate != 0) { // skip "dynamic" rates
- bool hasRate = false;
- for (size_t l = 0 ; l < mSamplingRates.size() ; l++) {
- if (rate == mSamplingRates.itemAt(l)) {
- hasRate = true;
+void AudioPort::importAudioPort(const sp<AudioPort> port)
+{
+ size_t indexToImport;
+ for (indexToImport = 0; indexToImport < port->mProfiles.size(); indexToImport++) {
+ const sp<AudioProfile> &profileToImport = port->mProfiles[indexToImport];
+ if (profileToImport->isValid()) {
+ // Import only valid port, i.e. valid format, non empty rates and channels masks
+ bool hasSameProfile = false;
+ for (size_t profileIndex = 0; profileIndex < mProfiles.size(); profileIndex++) {
+ if (*mProfiles[profileIndex] == *profileToImport) {
+ // never import a profile twice
+ hasSameProfile = true;
break;
}
}
- if (!hasRate) { // never import a sampling rate twice
- mSamplingRates.add(rate);
+ if (hasSameProfile) { // never import a same profile twice
+ continue;
}
- }
- }
- for (size_t k = 0 ; k < port->mChannelMasks.size() ; k++) {
- const audio_channel_mask_t mask = port->mChannelMasks.itemAt(k);
- if (mask != 0) { // skip "dynamic" masks
- bool hasMask = false;
- for (size_t l = 0 ; l < mChannelMasks.size() ; l++) {
- if (mask == mChannelMasks.itemAt(l)) {
- hasMask = true;
- break;
- }
- }
- if (!hasMask) { // never import a channel mask twice
- mChannelMasks.add(mask);
- }
- }
- }
- for (size_t k = 0 ; k < port->mFormats.size() ; k++) {
- const audio_format_t format = port->mFormats.itemAt(k);
- if (format != 0) { // skip "dynamic" formats
- bool hasFormat = false;
- for (size_t l = 0 ; l < mFormats.size() ; l++) {
- if (format == mFormats.itemAt(l)) {
- hasFormat = true;
- break;
- }
- }
- if (!hasFormat) { // never import a format twice
- mFormats.add(format);
- }
+ addAudioProfile(profileToImport);
}
}
}
-void AudioPort::clearCapabilities() {
- mChannelMasks.clear();
- mFormats.clear();
- mSamplingRates.clear();
-}
-
-void AudioPort::setSupportedFormats(const Vector <audio_format_t> &formats)
+void AudioPort::pickSamplingRate(uint32_t &pickedRate,const SampleRateVector &samplingRates) const
{
- mFormats = formats;
- // we sort from worst to best, so that AUDIO_FORMAT_DEFAULT is always the first entry.
- // TODO: compareFormats could be a lambda to convert between pointer-to-format to format:
- // [](const audio_format_t *format1, const audio_format_t *format2) {
- // return compareFormats(*format1, *format2);
- // }
- mFormats.sort(compareFormats);
-}
-
-status_t AudioPort::checkExactSamplingRate(uint32_t samplingRate) const
-{
- if (mSamplingRates.isEmpty()) {
- return NO_ERROR;
- }
-
- for (size_t i = 0; i < mSamplingRates.size(); i ++) {
- if (mSamplingRates[i] == samplingRate) {
- return NO_ERROR;
- }
- }
- return BAD_VALUE;
-}
-
-status_t AudioPort::checkCompatibleSamplingRate(uint32_t samplingRate,
- uint32_t *updatedSamplingRate) const
-{
- if (mSamplingRates.isEmpty()) {
- if (updatedSamplingRate != NULL) {
- *updatedSamplingRate = samplingRate;
- }
- return NO_ERROR;
- }
-
- // 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 do not need to be sorted in ascending order.
- ssize_t maxBelow = -1;
- ssize_t minAbove = -1;
- uint32_t candidate;
- for (size_t i = 0; i < mSamplingRates.size(); i++) {
- candidate = mSamplingRates[i];
- if (candidate == samplingRate) {
- if (updatedSamplingRate != NULL) {
- *updatedSamplingRate = candidate;
- }
- return NO_ERROR;
- }
- // candidate < desired
- if (candidate < samplingRate) {
- if (maxBelow < 0 || candidate > mSamplingRates[maxBelow]) {
- maxBelow = i;
- }
- // candidate > desired
- } else {
- if (minAbove < 0 || candidate < mSamplingRates[minAbove]) {
- minAbove = i;
- }
- }
- }
-
- // Prefer to down-sample from a higher sampling rate, as we get the desired frequency spectrum.
- if (minAbove >= 0) {
- candidate = mSamplingRates[minAbove];
- if (candidate / AUDIO_RESAMPLER_DOWN_RATIO_MAX <= samplingRate) {
- if (updatedSamplingRate != NULL) {
- *updatedSamplingRate = candidate;
- }
- return NO_ERROR;
- }
- }
- // But if we have to up-sample from a lower sampling rate, that's OK.
- if (maxBelow >= 0) {
- candidate = mSamplingRates[maxBelow];
- if (candidate * AUDIO_RESAMPLER_UP_RATIO_MAX >= samplingRate) {
- if (updatedSamplingRate != NULL) {
- *updatedSamplingRate = candidate;
- }
- return NO_ERROR;
- }
- }
- // leave updatedSamplingRate unmodified
- return BAD_VALUE;
-}
-
-status_t AudioPort::checkExactChannelMask(audio_channel_mask_t channelMask) const
-{
- if (mChannelMasks.isEmpty()) {
- return NO_ERROR;
- }
-
- for (size_t i = 0; i < mChannelMasks.size(); i++) {
- if (mChannelMasks[i] == channelMask) {
- return NO_ERROR;
- }
- }
- return BAD_VALUE;
-}
-
-status_t AudioPort::checkCompatibleChannelMask(audio_channel_mask_t channelMask,
- audio_channel_mask_t *updatedChannelMask) const
-{
- if (mChannelMasks.isEmpty()) {
- if (updatedChannelMask != NULL) {
- *updatedChannelMask = channelMask;
- }
- return NO_ERROR;
- }
-
- const bool isRecordThread = mType == AUDIO_PORT_TYPE_MIX && mRole == AUDIO_PORT_ROLE_SINK;
- const bool isIndex = audio_channel_mask_get_representation(channelMask)
- == AUDIO_CHANNEL_REPRESENTATION_INDEX;
- int bestMatch = 0;
- for (size_t i = 0; i < mChannelMasks.size(); i ++) {
- audio_channel_mask_t supported = mChannelMasks[i];
- if (supported == channelMask) {
- // Exact matches always taken.
- if (updatedChannelMask != NULL) {
- *updatedChannelMask = channelMask;
- }
- return NO_ERROR;
- }
-
- // AUDIO_CHANNEL_NONE (value: 0) is used for dynamic channel support
- if (isRecordThread && supported != AUDIO_CHANNEL_NONE) {
- // Approximate (best) match:
- // The match score measures how well the supported channel mask matches the
- // desired mask, where increasing-is-better.
- //
- // TODO: Some tweaks may be needed.
- // Should be a static function of the data processing library.
- //
- // In priority:
- // match score = 1000 if legacy channel conversion equivalent (always prefer this)
- // OR
- // match score += 100 if the channel mask representations match
- // match score += number of channels matched.
- //
- // If there are no matched channels, the mask may still be accepted
- // but the playback or record will be silent.
- const bool isSupportedIndex = (audio_channel_mask_get_representation(supported)
- == AUDIO_CHANNEL_REPRESENTATION_INDEX);
- int match;
- if (isIndex && isSupportedIndex) {
- // index equivalence
- match = 100 + __builtin_popcount(
- audio_channel_mask_get_bits(channelMask)
- & audio_channel_mask_get_bits(supported));
- } else if (isIndex && !isSupportedIndex) {
- const uint32_t equivalentBits =
- (1 << audio_channel_count_from_in_mask(supported)) - 1 ;
- match = __builtin_popcount(
- audio_channel_mask_get_bits(channelMask) & equivalentBits);
- } else if (!isIndex && isSupportedIndex) {
- const uint32_t equivalentBits =
- (1 << audio_channel_count_from_in_mask(channelMask)) - 1;
- match = __builtin_popcount(
- equivalentBits & audio_channel_mask_get_bits(supported));
- } else {
- // positional equivalence
- match = 100 + __builtin_popcount(
- audio_channel_mask_get_bits(channelMask)
- & audio_channel_mask_get_bits(supported));
- switch (supported) {
- case AUDIO_CHANNEL_IN_FRONT_BACK:
- case AUDIO_CHANNEL_IN_STEREO:
- if (channelMask == AUDIO_CHANNEL_IN_MONO) {
- match = 1000;
- }
- break;
- case AUDIO_CHANNEL_IN_MONO:
- if (channelMask == AUDIO_CHANNEL_IN_FRONT_BACK
- || channelMask == AUDIO_CHANNEL_IN_STEREO) {
- match = 1000;
- }
- break;
- default:
- break;
- }
- }
- if (match > bestMatch) {
- bestMatch = match;
- if (updatedChannelMask != NULL) {
- *updatedChannelMask = supported;
- } else {
- return NO_ERROR; // any match will do in this case.
- }
- }
- }
- }
- return bestMatch > 0 ? NO_ERROR : BAD_VALUE;
-}
-
-status_t AudioPort::checkExactFormat(audio_format_t format) const
-{
- if (mFormats.isEmpty()) {
- return NO_ERROR;
- }
-
- for (size_t i = 0; i < mFormats.size(); i ++) {
- if (mFormats[i] == format) {
- return NO_ERROR;
- }
- }
- return BAD_VALUE;
-}
-
-status_t AudioPort::checkCompatibleFormat(audio_format_t format, audio_format_t *updatedFormat)
- const
-{
- if (mFormats.isEmpty()) {
- if (updatedFormat != NULL) {
- *updatedFormat = format;
- }
- return NO_ERROR;
- }
-
- const bool checkInexact = // when port is input and format is linear pcm
- mType == AUDIO_PORT_TYPE_MIX && mRole == AUDIO_PORT_ROLE_SINK
- && audio_is_linear_pcm(format);
-
- // iterate from best format to worst format (reverse order)
- for (ssize_t i = mFormats.size() - 1; i >= 0 ; --i) {
- if (mFormats[i] == format ||
- (checkInexact
- && mFormats[i] != AUDIO_FORMAT_DEFAULT
- && audio_is_linear_pcm(mFormats[i]))) {
- // for inexact checks we take the first linear pcm format due to sorting.
- if (updatedFormat != NULL) {
- *updatedFormat = mFormats[i];
- }
- return NO_ERROR;
- }
- }
- return BAD_VALUE;
-}
-
-uint32_t AudioPort::pickSamplingRate() const
-{
- // special case for uninitialized dynamic profile
- if (mSamplingRates.size() == 1 && mSamplingRates[0] == 0) {
- return 0;
- }
-
+ pickedRate = 0;
// For direct outputs, pick minimum sampling rate: this helps ensuring that the
// channel count / sampling rate combination chosen will be supported by the connected
// sink
- if ((mType == AUDIO_PORT_TYPE_MIX) && (mRole == AUDIO_PORT_ROLE_SOURCE) &&
- (mFlags & (AUDIO_OUTPUT_FLAG_DIRECT | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD))) {
+ if (isDirectOutput()) {
uint32_t samplingRate = UINT_MAX;
- for (size_t i = 0; i < mSamplingRates.size(); i ++) {
- if ((mSamplingRates[i] < samplingRate) && (mSamplingRates[i] > 0)) {
- samplingRate = mSamplingRates[i];
+ for (size_t i = 0; i < samplingRates.size(); i ++) {
+ if ((samplingRates[i] < samplingRate) && (samplingRates[i] > 0)) {
+ samplingRate = samplingRates[i];
}
}
- return (samplingRate == UINT_MAX) ? 0 : samplingRate;
- }
+ pickedRate = (samplingRate == UINT_MAX) ? 0 : samplingRate;
+ } else {
+ uint32_t maxRate = MAX_MIXER_SAMPLING_RATE;
- uint32_t samplingRate = 0;
- uint32_t maxRate = MAX_MIXER_SAMPLING_RATE;
-
- // For mixed output and inputs, use max mixer sampling rates. Do not
- // limit sampling rate otherwise
- // For inputs, also see checkCompatibleSamplingRate().
- if (mType != AUDIO_PORT_TYPE_MIX) {
- maxRate = UINT_MAX;
- }
- // TODO: should mSamplingRates[] be ordered in terms of our preference
- // and we return the first (and hence most preferred) match? This is of concern if
- // we want to choose 96kHz over 192kHz for USB driver stability or resource constraints.
- for (size_t i = 0; i < mSamplingRates.size(); i ++) {
- if ((mSamplingRates[i] > samplingRate) && (mSamplingRates[i] <= maxRate)) {
- samplingRate = mSamplingRates[i];
+ // For mixed output and inputs, use max mixer sampling rates. Do not
+ // limit sampling rate otherwise
+ // For inputs, also see checkCompatibleSamplingRate().
+ if (mType != AUDIO_PORT_TYPE_MIX) {
+ maxRate = UINT_MAX;
+ }
+ // TODO: should mSamplingRates[] be ordered in terms of our preference
+ // and we return the first (and hence most preferred) match? This is of concern if
+ // we want to choose 96kHz over 192kHz for USB driver stability or resource constraints.
+ for (size_t i = 0; i < samplingRates.size(); i ++) {
+ if ((samplingRates[i] > pickedRate) && (samplingRates[i] <= maxRate)) {
+ pickedRate = samplingRates[i];
+ }
}
}
- return samplingRate;
}
-audio_channel_mask_t AudioPort::pickChannelMask() const
+void AudioPort::pickChannelMask(audio_channel_mask_t &pickedChannelMask,
+ const ChannelsVector &channelMasks) const
{
- // special case for uninitialized dynamic profile
- if (mChannelMasks.size() == 1 && mChannelMasks[0] == 0) {
- return AUDIO_CHANNEL_NONE;
- }
- audio_channel_mask_t channelMask = AUDIO_CHANNEL_NONE;
-
+ pickedChannelMask = AUDIO_CHANNEL_NONE;
// For direct outputs, pick minimum channel count: this helps ensuring that the
// channel count / sampling rate combination chosen will be supported by the connected
// sink
- if ((mType == AUDIO_PORT_TYPE_MIX) && (mRole == AUDIO_PORT_ROLE_SOURCE) &&
- (mFlags & (AUDIO_OUTPUT_FLAG_DIRECT | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD))) {
+ if (isDirectOutput()) {
uint32_t channelCount = UINT_MAX;
- for (size_t i = 0; i < mChannelMasks.size(); i ++) {
+ for (size_t i = 0; i < channelMasks.size(); i ++) {
uint32_t cnlCount;
if (useInputChannelMask()) {
- cnlCount = audio_channel_count_from_in_mask(mChannelMasks[i]);
+ cnlCount = audio_channel_count_from_in_mask(channelMasks[i]);
} else {
- cnlCount = audio_channel_count_from_out_mask(mChannelMasks[i]);
+ cnlCount = audio_channel_count_from_out_mask(channelMasks[i]);
}
if ((cnlCount < channelCount) && (cnlCount > 0)) {
- channelMask = mChannelMasks[i];
+ pickedChannelMask = channelMasks[i];
channelCount = cnlCount;
}
}
- return channelMask;
- }
+ } else {
+ uint32_t channelCount = 0;
+ uint32_t maxCount = MAX_MIXER_CHANNEL_COUNT;
- uint32_t channelCount = 0;
- uint32_t maxCount = MAX_MIXER_CHANNEL_COUNT;
-
- // For mixed output and inputs, use max mixer channel count. Do not
- // limit channel count otherwise
- if (mType != AUDIO_PORT_TYPE_MIX) {
- maxCount = UINT_MAX;
- }
- for (size_t i = 0; i < mChannelMasks.size(); i ++) {
- uint32_t cnlCount;
- if (useInputChannelMask()) {
- cnlCount = audio_channel_count_from_in_mask(mChannelMasks[i]);
- } else {
- cnlCount = audio_channel_count_from_out_mask(mChannelMasks[i]);
+ // For mixed output and inputs, use max mixer channel count. Do not
+ // limit channel count otherwise
+ if (mType != AUDIO_PORT_TYPE_MIX) {
+ maxCount = UINT_MAX;
}
- if ((cnlCount > channelCount) && (cnlCount <= maxCount)) {
- channelMask = mChannelMasks[i];
- channelCount = cnlCount;
+ for (size_t i = 0; i < channelMasks.size(); i ++) {
+ uint32_t cnlCount;
+ if (useInputChannelMask()) {
+ cnlCount = audio_channel_count_from_in_mask(channelMasks[i]);
+ } else {
+ cnlCount = audio_channel_count_from_out_mask(channelMasks[i]);
+ }
+ if ((cnlCount > channelCount) && (cnlCount <= maxCount)) {
+ pickedChannelMask = channelMasks[i];
+ channelCount = cnlCount;
+ }
}
}
- return channelMask;
}
/* format in order of increasing preference */
@@ -494,8 +238,7 @@
AUDIO_FORMAT_PCM_FLOAT,
};
-int AudioPort::compareFormats(audio_format_t format1,
- audio_format_t format2)
+int AudioPort::compareFormats(audio_format_t format1, audio_format_t format2)
{
// NOTE: AUDIO_FORMAT_INVALID is also considered not PCM and will be compared equal to any
// compressed format and better than any PCM format. This is by design of pickFormat()
@@ -525,36 +268,49 @@
return index1 - index2;
}
-audio_format_t AudioPort::pickFormat() const
+void AudioPort::pickAudioProfile(uint32_t &samplingRate,
+ audio_channel_mask_t &channelMask,
+ audio_format_t &format) const
{
- // special case for uninitialized dynamic profile
- if (mFormats.size() == 1 && mFormats[0] == 0) {
- return AUDIO_FORMAT_DEFAULT;
- }
+ format = AUDIO_FORMAT_DEFAULT;
+ samplingRate = 0;
+ channelMask = AUDIO_CHANNEL_NONE;
- audio_format_t format = AUDIO_FORMAT_DEFAULT;
- audio_format_t bestFormat =
- AudioPort::sPcmFormatCompareTable[
- ARRAY_SIZE(AudioPort::sPcmFormatCompareTable) - 1];
- // For mixed output and inputs, use best mixer output format. Do not
- // limit format otherwise
- if ((mType != AUDIO_PORT_TYPE_MIX) ||
- ((mRole == AUDIO_PORT_ROLE_SOURCE) &&
- (((mFlags & (AUDIO_OUTPUT_FLAG_DIRECT | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)) != 0)))) {
+ // special case for uninitialized dynamic profile
+ if (!mProfiles.hasValidProfile()) {
+ return;
+ }
+ audio_format_t bestFormat = sPcmFormatCompareTable[ARRAY_SIZE(sPcmFormatCompareTable) - 1];
+ // For mixed output and inputs, use best mixer output format.
+ // Do not limit format otherwise
+ if ((mType != AUDIO_PORT_TYPE_MIX) || isDirectOutput()) {
bestFormat = AUDIO_FORMAT_INVALID;
}
- for (size_t i = 0; i < mFormats.size(); i ++) {
- if ((compareFormats(mFormats[i], format) > 0) &&
- (compareFormats(mFormats[i], bestFormat) <= 0)) {
- format = mFormats[i];
+ for (size_t i = 0; i < mProfiles.size(); i ++) {
+ if (!mProfiles[i]->isValid()) {
+ continue;
+ }
+ audio_format_t formatToCompare = mProfiles[i]->getFormat();
+ if ((compareFormats(formatToCompare, format) > 0) &&
+ (compareFormats(formatToCompare, bestFormat) <= 0)) {
+ uint32_t pickedSamplingRate = 0;
+ audio_channel_mask_t pickedChannelMask = AUDIO_CHANNEL_NONE;
+ pickChannelMask(pickedChannelMask, mProfiles[i]->getChannels());
+ pickSamplingRate(pickedSamplingRate, mProfiles[i]->getSampleRates());
+
+ if (formatToCompare != AUDIO_FORMAT_DEFAULT && pickedChannelMask != AUDIO_CHANNEL_NONE
+ && pickedSamplingRate != 0) {
+ format = formatToCompare;
+ channelMask = pickedChannelMask;
+ samplingRate = pickedSamplingRate;
+ // TODO: shall we return on the first one or still trying to pick a better Profile?
+ }
}
}
- return format;
}
-status_t AudioPort::checkGain(const struct audio_gain_config *gainConfig,
- int index) const
+status_t AudioPort::checkGain(const struct audio_gain_config *gainConfig, int index) const
{
if (index < 0 || (size_t)index >= mGains.size()) {
return BAD_VALUE;
@@ -562,7 +318,7 @@
return mGains[index]->checkConfig(gainConfig);
}
-void AudioPort::dump(int fd, int spaces) const
+void AudioPort::dump(int fd, int spaces, bool verbose) const
{
const size_t SIZE = 256;
char buffer[SIZE];
@@ -571,66 +327,17 @@
if (mName.length() != 0) {
snprintf(buffer, SIZE, "%*s- name: %s\n", spaces, "", mName.string());
result.append(buffer);
+ write(fd, result.string(), result.size());
}
+ if (verbose) {
+ mProfiles.dump(fd, spaces);
- if (mSamplingRates.size() != 0) {
- snprintf(buffer, SIZE, "%*s- sampling rates: ", spaces, "");
- result.append(buffer);
- for (size_t i = 0; i < mSamplingRates.size(); i++) {
- if (i == 0 && mSamplingRates[i] == 0) {
- snprintf(buffer, SIZE, "Dynamic");
- } else {
- snprintf(buffer, SIZE, "%d", mSamplingRates[i]);
+ if (mGains.size() != 0) {
+ snprintf(buffer, SIZE, "%*s- gains:\n", spaces, "");
+ write(fd, buffer, strlen(buffer) + 1);
+ for (size_t i = 0; i < mGains.size(); i++) {
+ mGains[i]->dump(fd, spaces + 2, i);
}
- result.append(buffer);
- result.append(i == (mSamplingRates.size() - 1) ? "" : ", ");
- }
- result.append("\n");
- }
-
- if (mChannelMasks.size() != 0) {
- snprintf(buffer, SIZE, "%*s- channel masks: ", spaces, "");
- result.append(buffer);
- for (size_t i = 0; i < mChannelMasks.size(); i++) {
- ALOGV("AudioPort::dump mChannelMasks %zu %08x", i, mChannelMasks[i]);
-
- if (i == 0 && mChannelMasks[i] == 0) {
- snprintf(buffer, SIZE, "Dynamic");
- } else {
- snprintf(buffer, SIZE, "0x%04x", mChannelMasks[i]);
- }
- result.append(buffer);
- result.append(i == (mChannelMasks.size() - 1) ? "" : ", ");
- }
- result.append("\n");
- }
-
- if (mFormats.size() != 0) {
- snprintf(buffer, SIZE, "%*s- formats: ", spaces, "");
- result.append(buffer);
- for (size_t i = 0; i < mFormats.size(); i++) {
- std::string formatLiteral;
- bool success = FormatConverter::toString(mFormats[i], formatLiteral);
- if (i == 0 && !success) {
- snprintf(buffer, SIZE, "Dynamic");
- } else {
- if (!success) {
- snprintf(buffer, SIZE, "%#x", mFormats[i]);
- } else {
- snprintf(buffer, SIZE, "%s", formatLiteral.c_str());
- }
- }
- result.append(buffer);
- result.append(i == (mFormats.size() - 1) ? "" : ", ");
- }
- result.append("\n");
- }
- write(fd, result.string(), result.size());
- if (mGains.size() != 0) {
- snprintf(buffer, SIZE, "%*s- gains:\n", spaces, "");
- write(fd, buffer, strlen(buffer) + 1);
- for (size_t i = 0; i < mGains.size(); i++) {
- mGains[i]->dump(fd, spaces + 2, i);
}
}
}
@@ -650,9 +357,8 @@
mGain.index = -1;
}
-status_t AudioPortConfig::applyAudioPortConfig(
- const struct audio_port_config *config,
- struct audio_port_config *backupConfig)
+status_t AudioPortConfig::applyAudioPortConfig(const struct audio_port_config *config,
+ struct audio_port_config *backupConfig)
{
struct audio_port_config localBackupConfig;
status_t status = NO_ERROR;
@@ -665,25 +371,19 @@
status = NO_INIT;
goto exit;
}
+ status = audioport->checkExactAudioProfile(config->sample_rate,
+ config->channel_mask,
+ config->format);
+ if (status != NO_ERROR) {
+ goto exit;
+ }
if (config->config_mask & AUDIO_PORT_CONFIG_SAMPLE_RATE) {
- status = audioport->checkExactSamplingRate(config->sample_rate);
- if (status != NO_ERROR) {
- goto exit;
- }
mSamplingRate = config->sample_rate;
}
if (config->config_mask & AUDIO_PORT_CONFIG_CHANNEL_MASK) {
- status = audioport->checkExactChannelMask(config->channel_mask);
- if (status != NO_ERROR) {
- goto exit;
- }
mChannelMask = config->channel_mask;
}
if (config->config_mask & AUDIO_PORT_CONFIG_FORMAT) {
- status = audioport->checkExactFormat(config->format);
- if (status != NO_ERROR) {
- goto exit;
- }
mFormat = config->format;
}
if (config->config_mask & AUDIO_PORT_CONFIG_GAIN) {
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioProfile.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioProfile.cpp
new file mode 100644
index 0000000..c599665
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioProfile.cpp
@@ -0,0 +1,288 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "APM::AudioProfile"
+//#define LOG_NDEBUG 0
+
+#include "AudioProfile.h"
+#include "AudioPort.h"
+#include "HwModule.h"
+#include "AudioGain.h"
+#include <utils/SortedVector.h>
+#include "TypeConverter.h"
+#include <media/AudioResamplerPublic.h>
+#include <algorithm>
+
+namespace android {
+
+status_t AudioProfile::checkExact(uint32_t samplingRate, audio_channel_mask_t channelMask,
+ audio_format_t format) const
+{
+ if (format == mFormat &&
+ (mChannelMasks.isEmpty() || supportsChannels(channelMask)) &&
+ (mSamplingRates.isEmpty() || supportsRate(samplingRate))) {
+ return NO_ERROR;
+ }
+ return BAD_VALUE;
+}
+
+template <typename T>
+bool operator == (const SortedVector<T> &left, const SortedVector<T> &right)
+{
+ if (left.size() != right.size()) {
+ return false;
+ }
+ for(size_t index = 0; index < right.size(); index++) {
+ if (left[index] != right[index]) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool operator == (const AudioProfile &left, const AudioProfile &compareTo)
+{
+ return (left.getFormat() == compareTo.getFormat()) &&
+ (left.getChannels() == compareTo.getChannels()) &&
+ (left.getSampleRates() == compareTo.getSampleRates());
+}
+
+status_t AudioProfile::checkCompatibleSamplingRate(uint32_t samplingRate,
+ uint32_t &updatedSamplingRate) const
+{
+ if (mSamplingRates.isEmpty()) {
+ updatedSamplingRate = samplingRate;
+ return NO_ERROR;
+ }
+ // 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.
+ size_t orderOfDesiredRate = mSamplingRates.orderOf(samplingRate);
+
+ // Prefer to down-sample from a higher sampling rate, as we get the desired frequency spectrum.
+ if (orderOfDesiredRate < mSamplingRates.size()) {
+ uint32_t candidate = mSamplingRates[orderOfDesiredRate];
+ if (candidate / AUDIO_RESAMPLER_DOWN_RATIO_MAX <= samplingRate) {
+ updatedSamplingRate = candidate;
+ return NO_ERROR;
+ }
+ }
+ // But if we have to up-sample from a lower sampling rate, that's OK.
+ if (orderOfDesiredRate != 0) {
+ uint32_t candidate = mSamplingRates[orderOfDesiredRate - 1];
+ if (candidate * AUDIO_RESAMPLER_UP_RATIO_MAX >= samplingRate) {
+ updatedSamplingRate = candidate;
+ return NO_ERROR;
+ }
+ }
+ // leave updatedSamplingRate unmodified
+ 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
+{
+ if (mChannelMasks.isEmpty()) {
+ updatedChannelMask = channelMask;
+ return NO_ERROR;
+ }
+ const bool isRecordThread = portType == AUDIO_PORT_TYPE_MIX && portRole == AUDIO_PORT_ROLE_SINK;
+ const bool isIndex = audio_channel_mask_get_representation(channelMask)
+ == AUDIO_CHANNEL_REPRESENTATION_INDEX;
+ int bestMatch = 0;
+ for (size_t i = 0; i < mChannelMasks.size(); i ++) {
+ audio_channel_mask_t supported = mChannelMasks[i];
+ if (supported == channelMask) {
+ // Exact matches always taken.
+ updatedChannelMask = channelMask;
+ return NO_ERROR;
+ }
+
+ // AUDIO_CHANNEL_NONE (value: 0) is used for dynamic channel support
+ if (isRecordThread && supported != AUDIO_CHANNEL_NONE) {
+ // Approximate (best) match:
+ // The match score measures how well the supported channel mask matches the
+ // desired mask, where increasing-is-better.
+ //
+ // TODO: Some tweaks may be needed.
+ // Should be a static function of the data processing library.
+ //
+ // In priority:
+ // match score = 1000 if legacy channel conversion equivalent (always prefer this)
+ // OR
+ // match score += 100 if the channel mask representations match
+ // match score += number of channels matched.
+ //
+ // If there are no matched channels, the mask may still be accepted
+ // but the playback or record will be silent.
+ const bool isSupportedIndex = (audio_channel_mask_get_representation(supported)
+ == AUDIO_CHANNEL_REPRESENTATION_INDEX);
+ int match;
+ if (isIndex && isSupportedIndex) {
+ // index equivalence
+ match = 100 + __builtin_popcount(
+ audio_channel_mask_get_bits(channelMask)
+ & audio_channel_mask_get_bits(supported));
+ } else if (isIndex && !isSupportedIndex) {
+ const uint32_t equivalentBits =
+ (1 << audio_channel_count_from_in_mask(supported)) - 1 ;
+ match = __builtin_popcount(
+ audio_channel_mask_get_bits(channelMask) & equivalentBits);
+ } else if (!isIndex && isSupportedIndex) {
+ const uint32_t equivalentBits =
+ (1 << audio_channel_count_from_in_mask(channelMask)) - 1;
+ match = __builtin_popcount(
+ equivalentBits & audio_channel_mask_get_bits(supported));
+ } else {
+ // positional equivalence
+ match = 100 + __builtin_popcount(
+ audio_channel_mask_get_bits(channelMask)
+ & audio_channel_mask_get_bits(supported));
+ switch (supported) {
+ case AUDIO_CHANNEL_IN_FRONT_BACK:
+ case AUDIO_CHANNEL_IN_STEREO:
+ if (channelMask == AUDIO_CHANNEL_IN_MONO) {
+ match = 1000;
+ }
+ break;
+ case AUDIO_CHANNEL_IN_MONO:
+ if (channelMask == AUDIO_CHANNEL_IN_FRONT_BACK
+ || channelMask == AUDIO_CHANNEL_IN_STEREO) {
+ match = 1000;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ if (match > bestMatch) {
+ bestMatch = match;
+ updatedChannelMask = supported;
+ }
+ }
+ }
+ return bestMatch > 0 ? NO_ERROR : BAD_VALUE;
+}
+
+void AudioProfile::dump(int fd, int spaces) const
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+
+ snprintf(buffer, SIZE, "%s%s%s\n", mIsDynamicFormat ? "[dynamic format]" : "",
+ mIsDynamicChannels ? "[dynamic channels]" : "",
+ mIsDynamicRate ? "[dynamic rates]" : "");
+ result.append(buffer);
+ if (mName.length() != 0) {
+ snprintf(buffer, SIZE, "%*s- name: %s\n", spaces, "", mName.string());
+ result.append(buffer);
+ }
+ std::string formatLiteral;
+ if (FormatConverter::toString(mFormat, formatLiteral)) {
+ snprintf(buffer, SIZE, "%*s- format: %s\n", spaces, "", formatLiteral.c_str());
+ result.append(buffer);
+ }
+ if (!mSamplingRates.isEmpty()) {
+ snprintf(buffer, SIZE, "%*s- sampling rates:", spaces, "");
+ result.append(buffer);
+ for (size_t i = 0; i < mSamplingRates.size(); i++) {
+ snprintf(buffer, SIZE, "%d", mSamplingRates[i]);
+ result.append(buffer);
+ result.append(i == (mSamplingRates.size() - 1) ? "" : ", ");
+ }
+ result.append("\n");
+ }
+
+ if (!mChannelMasks.isEmpty()) {
+ snprintf(buffer, SIZE, "%*s- channel masks:", spaces, "");
+ result.append(buffer);
+ for (size_t i = 0; i < mChannelMasks.size(); i++) {
+ snprintf(buffer, SIZE, "0x%04x", mChannelMasks[i]);
+ result.append(buffer);
+ result.append(i == (mChannelMasks.size() - 1) ? "" : ", ");
+ }
+ result.append("\n");
+ }
+ write(fd, result.string(), result.size());
+}
+
+status_t AudioProfileVector::checkExactProfile(uint32_t samplingRate,
+ audio_channel_mask_t channelMask,
+ audio_format_t format) const
+{
+ if (isEmpty()) {
+ return NO_ERROR;
+ }
+
+ for (size_t i = 0; i < size(); i++) {
+ const sp<AudioProfile> profile = itemAt(i);
+ if (profile->checkExact(samplingRate, channelMask, format) == NO_ERROR) {
+ return NO_ERROR;
+ }
+ }
+ return BAD_VALUE;
+}
+
+status_t AudioProfileVector::checkCompatibleProfile(uint32_t &samplingRate,
+ audio_channel_mask_t &channelMask,
+ audio_format_t &format,
+ audio_port_type_t portType,
+ audio_port_role_t portRole) const
+{
+ if (isEmpty()) {
+ return NO_ERROR;
+ }
+
+ const bool checkInexact = // when port is input and format is linear pcm
+ portType == AUDIO_PORT_TYPE_MIX && portRole == AUDIO_PORT_ROLE_SINK
+ && audio_is_linear_pcm(format);
+
+ // iterate from best format to worst format (reverse order)
+ for (ssize_t i = size() - 1; i >= 0 ; --i) {
+ const sp<AudioProfile> profile = itemAt(i);
+ audio_format_t formatToCompare = profile->getFormat();
+ if (formatToCompare == format ||
+ (checkInexact
+ && formatToCompare != AUDIO_FORMAT_DEFAULT
+ && audio_is_linear_pcm(formatToCompare))) {
+ // Compatible profile has been found, checks if this profile has compatible
+ // 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) {
+ // for inexact checks we take the first linear pcm format due to sorting.
+ format = formatToCompare;
+ channelMask = updatedChannels;
+ samplingRate = updatedRate;
+ return NO_ERROR;
+ }
+ }
+ }
+ return BAD_VALUE;
+}
+
+int AudioProfileVector::compareFormats(const sp<AudioProfile> *profile1,
+ const sp<AudioProfile> *profile2)
+{
+ return AudioPort::compareFormats((*profile1)->getFormat(), (*profile2)->getFormat());
+}
+
+}; // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioSession.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioSession.cpp
new file mode 100644
index 0000000..2cec951
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioSession.cpp
@@ -0,0 +1,198 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "APM::AudioSession"
+//#define LOG_NDEBUG 0
+
+#include "AudioSession.h"
+#include "AudioGain.h"
+#include "TypeConverter.h"
+#include <cutils/log.h>
+#include <utils/String8.h>
+
+namespace android {
+
+AudioSession::AudioSession(audio_session_t session,
+ audio_source_t inputSource,
+ audio_format_t format,
+ uint32_t sampleRate,
+ audio_channel_mask_t channelMask,
+ audio_input_flags_t flags,
+ uid_t uid,
+ bool isSoundTrigger) :
+ mSession(session), mInputSource(inputSource),
+ mFormat(format), mSampleRate(sampleRate), mChannelMask(channelMask),
+ mFlags(flags), mUid(uid), mIsSoundTrigger(isSoundTrigger),
+ mOpenCount(1), mActiveCount(0)
+{
+}
+
+uint32_t AudioSession::changeOpenCount(int delta)
+{
+ if ((delta + (int)mOpenCount) < 0) {
+ ALOGW("%s invalid delta %d, open count %d",
+ __FUNCTION__, delta, mOpenCount);
+ mOpenCount = (uint32_t)(-delta);
+ }
+ mOpenCount += delta;
+ ALOGV("%s open count %d", __FUNCTION__, mOpenCount);
+ return mOpenCount;
+}
+
+uint32_t AudioSession::changeActiveCount(int delta)
+{
+ if ((delta + (int)mActiveCount) < 0) {
+ ALOGW("%s invalid delta %d, active count %d",
+ __FUNCTION__, delta, mActiveCount);
+ mActiveCount = (uint32_t)(-delta);
+ }
+ mActiveCount += delta;
+ ALOGV("%s active count %d", __FUNCTION__, mActiveCount);
+ return mActiveCount;
+}
+
+bool AudioSession::matches(const sp<AudioSession> &other) const
+{
+ if (other->session() == mSession &&
+ other->inputSource() == mInputSource &&
+ other->format() == mFormat &&
+ other->sampleRate() == mSampleRate &&
+ other->channelMask() == mChannelMask &&
+ other->flags() == mFlags &&
+ other->uid() == mUid) {
+ return true;
+ }
+ return false;
+}
+
+
+status_t AudioSession::dump(int fd, int spaces, int index) const
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+
+ snprintf(buffer, SIZE, "%*sAudio session %d:\n", spaces, "", index+1);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "%*s- session: %2d\n", spaces, "", mSession);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "%*s- owner uid: %2d\n", spaces, "", mUid);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "%*s- input source: %d\n", spaces, "", mInputSource);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "%*s- format: %08x\n", spaces, "", mFormat);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "%*s- sample: %d\n", spaces, "", mSampleRate);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "%*s- channel mask: %08x\n",
+ spaces, "", mChannelMask);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "%*s- is soundtrigger: %s\n",
+ spaces, "", mIsSoundTrigger ? "true" : "false");
+ result.append(buffer);
+ snprintf(buffer, SIZE, "%*s- open count: %d\n", spaces, "", mOpenCount);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "%*s- active count: %d\n", spaces, "", mActiveCount);
+ result.append(buffer);
+
+ write(fd, result.string(), result.size());
+ return NO_ERROR;
+}
+
+status_t AudioSessionCollection::addSession(audio_session_t session,
+ const sp<AudioSession>& audioSession)
+{
+ ssize_t index = indexOfKey(session);
+
+ if (index >= 0) {
+ ALOGW("addSession() session %d already in", session);
+ return ALREADY_EXISTS;
+ }
+ add(session, audioSession);
+ ALOGV("addSession() session %d client %d source %d",
+ session, audioSession->uid(), audioSession->inputSource());
+ return NO_ERROR;
+}
+
+status_t AudioSessionCollection::removeSession(audio_session_t session)
+{
+ ssize_t index = indexOfKey(session);
+
+ if (index < 0) {
+ ALOGW("removeSession() session %d not in", session);
+ return ALREADY_EXISTS;
+ }
+ ALOGV("removeSession() session %d", session);
+ removeItemsAt(index);
+ return NO_ERROR;
+}
+
+uint32_t AudioSessionCollection::getOpenCount() const
+{
+ uint32_t openCount = 0;
+ for (size_t i = 0; i < size(); i++) {
+ openCount += valueAt(i)->openCount();
+ }
+ return openCount;
+}
+
+AudioSessionCollection AudioSessionCollection::getActiveSessions() const
+{
+ AudioSessionCollection activeSessions;
+ for (size_t i = 0; i < size(); i++) {
+ if (valueAt(i)->activeCount() != 0) {
+ activeSessions.add(valueAt(i)->session(), valueAt(i));
+ }
+ }
+ return activeSessions;
+}
+
+bool AudioSessionCollection::hasActiveSession() const
+{
+ return getActiveSessions().size() != 0;
+}
+
+bool AudioSessionCollection::isSourceActive(audio_source_t source) const
+{
+ for (size_t i = 0; i < size(); i++) {
+ const sp<AudioSession> audioSession = valueAt(i);
+ // AUDIO_SOURCE_HOTWORD is equivalent to AUDIO_SOURCE_VOICE_RECOGNITION only if it
+ // corresponds to an active capture triggered by a hardware hotword recognition
+ if (audioSession->activeCount() > 0 &&
+ ((audioSession->inputSource() == source) ||
+ ((source == AUDIO_SOURCE_VOICE_RECOGNITION) &&
+ (audioSession->inputSource() == AUDIO_SOURCE_HOTWORD) &&
+ audioSession->isSoundTrigger()))) {
+ return true;
+ }
+ }
+ return false;
+}
+
+
+status_t AudioSessionCollection::dump(int fd, int spaces) const
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ snprintf(buffer, SIZE, "%*sAudio Sessions:\n", spaces, "");
+ write(fd, buffer, strlen(buffer));
+ for (size_t i = 0; i < size(); i++) {
+ valueAt(i)->dump(fd, spaces + 2, i);
+ }
+ return NO_ERROR;
+}
+
+}; // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/ConfigParsingUtils.cpp b/services/audiopolicy/common/managerdefinitions/src/ConfigParsingUtils.cpp
index 786c4e8..b187857 100644
--- a/services/audiopolicy/common/managerdefinitions/src/ConfigParsingUtils.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/ConfigParsingUtils.cpp
@@ -135,9 +135,15 @@
deviceDesc->mAddress = String8((char *)node->value);
} else if (strcmp(node->name, CHANNELS_TAG) == 0) {
if (audio_is_input_device(type)) {
- deviceDesc->setSupportedChannelMasks(inputChannelMasksFromString(node->value));
+ deviceDesc->addAudioProfile(
+ new AudioProfile(gDynamicFormat,
+ inputChannelMasksFromString(node->value),
+ SampleRateVector()));
} else {
- deviceDesc->setSupportedChannelMasks(outputChannelMasksFromString(node->value));
+ deviceDesc->addAudioProfile(
+ new AudioProfile(gDynamicFormat,
+ outputChannelMasksFromString(node->value),
+ SampleRateVector()));
}
} else if (strcmp(node->name, GAINS_TAG) == 0) {
loadDeviceDescriptorGains(node, deviceDesc);
@@ -153,95 +159,74 @@
}
//static
-status_t ConfigParsingUtils::loadHwModuleInput(cnode *root, sp<HwModule> &module)
+status_t ConfigParsingUtils::loadHwModuleProfile(cnode *root, sp<HwModule> &module,
+ audio_port_role_t role)
{
cnode *node = root->first_child;
- sp<InputProfile> profile = new InputProfile(String8(root->name));
+ sp<IOProfile> profile = new IOProfile(String8(root->name), role);
+
+ AudioProfileVector audioProfiles;
+ SampleRateVector sampleRates;
+ ChannelsVector channels;
+ FormatVector formats;
while (node) {
- if (strcmp(node->name, SAMPLING_RATES_TAG) == 0) {
- profile->setSupportedSamplingRates(samplingRatesFromString(node->value));
- } else if (strcmp(node->name, FORMATS_TAG) == 0) {
- profile->setSupportedFormats(formatsFromString(node->value));
- } else if (strcmp(node->name, CHANNELS_TAG) == 0) {
- profile->setSupportedChannelMasks(inputChannelMasksFromString(node->value));
+ if (strcmp(node->name, FORMATS_TAG) == 0 &&
+ strcmp(node->value, DYNAMIC_VALUE_TAG) != 0) {
+ formats = formatsFromString(node->value);
+ } else if (strcmp(node->name, SAMPLING_RATES_TAG) == 0 &&
+ strcmp(node->value, DYNAMIC_VALUE_TAG) != 0) {
+ collectionFromString<SampleRateTraits>(node->value, sampleRates);
+ } else if (strcmp(node->name, CHANNELS_TAG) == 0 &&
+ strcmp(node->value, DYNAMIC_VALUE_TAG) != 0) {
+ if (role == AUDIO_PORT_ROLE_SINK) {
+ channels = inputChannelMasksFromString(node->value);
+ } else {
+ channels = outputChannelMasksFromString(node->value);
+ }
} else if (strcmp(node->name, DEVICES_TAG) == 0) {
DeviceVector devices;
loadDevicesFromTag(node->value, devices, module->getDeclaredDevices());
profile->setSupportedDevices(devices);
} else if (strcmp(node->name, FLAGS_TAG) == 0) {
- profile->setFlags(InputFlagConverter::maskFromString(node->value));
+ if (role == AUDIO_PORT_ROLE_SINK) {
+ profile->setFlags(InputFlagConverter::maskFromString(node->value));
+ } else {
+ profile->setFlags(ConfigParsingUtils::parseOutputFlagNames(node->value));
+ }
} else if (strcmp(node->name, GAINS_TAG) == 0) {
loadAudioPortGains(node, *profile);
}
node = node->next;
}
- ALOGW_IF(profile->getSupportedDevices().isEmpty(),
- "loadInput() invalid supported devices");
- ALOGW_IF(profile->mChannelMasks.size() == 0,
- "loadInput() invalid supported channel masks");
- ALOGW_IF(profile->mSamplingRates.size() == 0,
- "loadInput() invalid supported sampling rates");
- ALOGW_IF(profile->mFormats.size() == 0,
- "loadInput() invalid supported formats");
- if (!profile->getSupportedDevices().isEmpty() &&
- (profile->mChannelMasks.size() != 0) &&
- (profile->mSamplingRates.size() != 0) &&
- (profile->mFormats.size() != 0)) {
-
- ALOGV("loadInput() adding input Supported Devices %04x",
- profile->getSupportedDevices().types());
- return module->addInputProfile(profile);
+ if (formats.isEmpty()) {
+ sp<AudioProfile> profileToAdd = new AudioProfile(gDynamicFormat, channels, sampleRates);
+ profileToAdd->setDynamicFormat(true);
+ profileToAdd->setDynamicChannels(channels.isEmpty());
+ profileToAdd->setDynamicRate(sampleRates.isEmpty());
+ audioProfiles.add(profileToAdd);
} else {
- return BAD_VALUE;
- }
-}
-
-//static
-status_t ConfigParsingUtils::loadHwModuleOutput(cnode *root, sp<HwModule> &module)
-{
- cnode *node = root->first_child;
-
- sp<OutputProfile> profile = new OutputProfile(String8(root->name));
-
- while (node) {
- if (strcmp(node->name, SAMPLING_RATES_TAG) == 0) {
- profile->setSupportedSamplingRates(samplingRatesFromString(node->value));
- } else if (strcmp(node->name, FORMATS_TAG) == 0) {
- profile->setSupportedFormats(formatsFromString(node->value));
- } else if (strcmp(node->name, CHANNELS_TAG) == 0) {
- profile->setSupportedChannelMasks(outputChannelMasksFromString(node->value));
- } else if (strcmp(node->name, DEVICES_TAG) == 0) {
- DeviceVector devices;
- loadDevicesFromTag(node->value, devices, module->getDeclaredDevices());
- profile->setSupportedDevices(devices);
- } else if (strcmp(node->name, FLAGS_TAG) == 0) {
- profile->setFlags(ConfigParsingUtils::parseOutputFlagNames(node->value));
- } else if (strcmp(node->name, GAINS_TAG) == 0) {
- loadAudioPortGains(node, *profile);
+ for (size_t i = 0; i < formats.size(); i++) {
+ // For compatibility reason, for each format, creates a profile with the same
+ // collection of rate and channels.
+ sp<AudioProfile> profileToAdd = new AudioProfile(formats[i], channels, sampleRates);
+ profileToAdd->setDynamicFormat(formats[i] == gDynamicFormat);
+ profileToAdd->setDynamicChannels(channels.isEmpty());
+ profileToAdd->setDynamicRate(sampleRates.isEmpty());
+ audioProfiles.add(profileToAdd);
}
- node = node->next;
}
- ALOGW_IF(profile->getSupportedDevices().isEmpty(),
- "loadOutput() invalid supported devices");
- ALOGW_IF(profile->mChannelMasks.size() == 0,
- "loadOutput() invalid supported channel masks");
- ALOGW_IF(profile->mSamplingRates.size() == 0,
- "loadOutput() invalid supported sampling rates");
- ALOGW_IF(profile->mFormats.size() == 0,
- "loadOutput() invalid supported formats");
- if (!profile->getSupportedDevices().isEmpty() &&
- (profile->mChannelMasks.size() != 0) &&
- (profile->mSamplingRates.size() != 0) &&
- (profile->mFormats.size() != 0)) {
-
- ALOGV("loadOutput() adding output Supported Devices %04x, mFlags %04x",
- profile->getSupportedDevices().types(), profile->getFlags());
- return module->addOutputProfile(profile);
- } else {
- return BAD_VALUE;
+ profile->setAudioProfiles(audioProfiles);
+ ALOGW_IF(!profile->hasSupportedDevices(), "load%s() invalid supported devices",
+ role == AUDIO_PORT_ROLE_SINK ? "Input" : "Output");
+ if (profile->hasSupportedDevices()) {
+ ALOGV("load%s() adding Supported Devices %04x, mFlags %04x",
+ role == AUDIO_PORT_ROLE_SINK ? "Input" : "Output",
+ profile->getSupportedDevicesType(), profile->getFlags());
+ return module->addProfile(profile);
}
+ return BAD_VALUE;
}
//static
@@ -268,7 +253,7 @@
node = node->first_child;
while (node) {
ALOGV("loadHwModule() loading output %s", node->name);
- status_t tmpStatus = loadHwModuleOutput(node, module);
+ status_t tmpStatus = loadHwModuleProfile(node, module, AUDIO_PORT_ROLE_SOURCE);
if (status == NAME_NOT_FOUND || status == NO_ERROR) {
status = tmpStatus;
}
@@ -280,7 +265,7 @@
node = node->first_child;
while (node) {
ALOGV("loadHwModule() loading input %s", node->name);
- status_t tmpStatus = loadHwModuleInput(node, module);
+ status_t tmpStatus = loadHwModuleProfile(node, module, AUDIO_PORT_ROLE_SINK);
if (status == NAME_NOT_FOUND || status == NO_ERROR) {
status = tmpStatus;
}
diff --git a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
index f7ddb35..d752485 100644
--- a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
@@ -207,15 +207,18 @@
return device;
}
-status_t DeviceVector::dump(int fd, const String8 &direction) const
+status_t DeviceVector::dump(int fd, const String8 &tag, int spaces, bool verbose) const
{
+ if (isEmpty()) {
+ return NO_ERROR;
+ }
const size_t SIZE = 256;
char buffer[SIZE];
- snprintf(buffer, SIZE, "\n Available %s devices:\n", direction.string());
+ snprintf(buffer, SIZE, "%*s %s devices:\n", spaces, "", tag.string());
write(fd, buffer, strlen(buffer));
for (size_t i = 0; i < size(); i++) {
- itemAt(i)->dump(fd, 2, i);
+ itemAt(i)->dump(fd, spaces + 4, i, verbose);
}
return NO_ERROR;
}
@@ -263,12 +266,10 @@
void DeviceDescriptor::importAudioPort(const sp<AudioPort> port) {
AudioPort::importAudioPort(port);
- mSamplingRate = port->pickSamplingRate();
- mFormat = port->pickFormat();
- mChannelMask = port->pickChannelMask();
+ port->pickAudioProfile(mSamplingRate, mChannelMask, mFormat);
}
-status_t DeviceDescriptor::dump(int fd, int spaces, int index) const
+status_t DeviceDescriptor::dump(int fd, int spaces, int index, bool verbose) const
{
const size_t SIZE = 256;
char buffer[SIZE];
@@ -290,7 +291,7 @@
result.append(buffer);
}
write(fd, result.string(), result.size());
- AudioPort::dump(fd, spaces);
+ AudioPort::dump(fd, spaces, verbose);
return NO_ERROR;
}
diff --git a/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
index 8b11361..dce0890 100644
--- a/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
@@ -43,13 +43,12 @@
}
status_t HwModule::addOutputProfile(String8 name, const audio_config_t *config,
- audio_devices_t device, String8 address)
+ audio_devices_t device, String8 address)
{
sp<IOProfile> profile = new OutputProfile(name);
- profile->mSamplingRates.add(config->sample_rate);
- profile->mChannelMasks.add(config->channel_mask);
- profile->mFormats.add(config->format);
+ profile->addAudioProfile(new AudioProfile(config->format, config->channel_mask,
+ config->sample_rate));
sp<DeviceDescriptor> devDesc = new DeviceDescriptor(device);
devDesc->mAddress = address;
@@ -105,13 +104,11 @@
}
status_t HwModule::addInputProfile(String8 name, const audio_config_t *config,
- audio_devices_t device, String8 address)
+ audio_devices_t device, String8 address)
{
sp<IOProfile> profile = new InputProfile(name);
-
- profile->mSamplingRates.add(config->sample_rate);
- profile->mChannelMasks.add(config->channel_mask);
- profile->mFormats.add(config->format);
+ profile->addAudioProfile(new AudioProfile(config->format, config->channel_mask,
+ config->sample_rate));
sp<DeviceDescriptor> devDesc = new DeviceDescriptor(device);
devDesc->mAddress = address;
@@ -165,12 +162,7 @@
mInputProfiles[i]->dump(fd);
}
}
- if (mDeclaredDevices.size()) {
- write(fd, " - devices:\n", strlen(" - devices:\n"));
- for (size_t i = 0; i < mDeclaredDevices.size(); i++) {
- mDeclaredDevices[i]->dump(fd, 4, i);
- }
- }
+ mDeclaredDevices.dump(fd, String8("Declared"), 2, true);
}
sp <HwModule> HwModuleCollection::getModuleFromName(const char *name) const
diff --git a/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp b/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp
index d41d239..fe38f54 100644
--- a/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp
@@ -20,6 +20,7 @@
#include "IOProfile.h"
#include "HwModule.h"
#include "AudioGain.h"
+#include "TypeConverter.h"
namespace android {
@@ -63,37 +64,25 @@
}
}
- if (samplingRate == 0) {
- return false;
- }
- uint32_t myUpdatedSamplingRate = samplingRate;
- if (isPlaybackThread && checkExactSamplingRate(samplingRate) != NO_ERROR) {
- return false;
- }
- if (isRecordThread && checkCompatibleSamplingRate(samplingRate, &myUpdatedSamplingRate) !=
- NO_ERROR) {
+ if (samplingRate == 0 || !audio_is_valid_format(format) ||
+ (isPlaybackThread && (!audio_is_output_channel(channelMask))) ||
+ (isRecordThread && (!audio_is_input_channel(channelMask)))) {
return false;
}
- if (!audio_is_valid_format(format)) {
- return false;
- }
- if (isPlaybackThread && checkExactFormat(format) != NO_ERROR) {
- return false;
- }
audio_format_t myUpdatedFormat = format;
- if (isRecordThread && checkCompatibleFormat(format, &myUpdatedFormat) != NO_ERROR) {
- return false;
- }
-
- if (isPlaybackThread && (!audio_is_output_channel(channelMask) ||
- checkExactChannelMask(channelMask) != NO_ERROR)) {
- return false;
- }
audio_channel_mask_t myUpdatedChannelMask = channelMask;
- if (isRecordThread && (!audio_is_input_channel(channelMask) ||
- checkCompatibleChannelMask(channelMask, &myUpdatedChannelMask) != NO_ERROR)) {
- return false;
+ uint32_t myUpdatedSamplingRate = samplingRate;
+ if (isRecordThread)
+ {
+ if (checkCompatibleAudioProfile(
+ myUpdatedSamplingRate, myUpdatedChannelMask, myUpdatedFormat) != NO_ERROR) {
+ return false;
+ }
+ } else {
+ if (checkExactAudioProfile(samplingRate, channelMask, format) != NO_ERROR) {
+ return false;
+ }
}
if (isPlaybackThread && (getFlags() & flags) != flags) {
@@ -130,37 +119,13 @@
snprintf(buffer, SIZE, " - flags: 0x%04x\n", getFlags());
result.append(buffer);
- snprintf(buffer, SIZE, " - devices:\n");
- result.append(buffer);
write(fd, result.string(), result.size());
- for (size_t i = 0; i < mSupportedDevices.size(); i++) {
- mSupportedDevices[i]->dump(fd, 6, i);
- }
+ mSupportedDevices.dump(fd, String8("- Supported"), 2, false);
}
void IOProfile::log()
{
- const size_t SIZE = 256;
- char buffer[SIZE];
- String8 result;
-
- ALOGV(" - sampling rates: ");
- for (size_t i = 0; i < mSamplingRates.size(); i++) {
- ALOGV(" %d", mSamplingRates[i]);
- }
-
- ALOGV(" - channel masks: ");
- for (size_t i = 0; i < mChannelMasks.size(); i++) {
- ALOGV(" 0x%04x", mChannelMasks[i]);
- }
-
- ALOGV(" - formats: ");
- for (size_t i = 0; i < mFormats.size(); i++) {
- ALOGV(" 0x%08x", mFormats[i]);
- }
-
- ALOGV(" - devices: 0x%04x\n", mSupportedDevices.types());
- ALOGV(" - flags: 0x%04x\n", getFlags());
+ // @TODO: forward log to AudioPort
}
}; // namespace android
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 4a67c4a..11dabae 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -418,7 +418,9 @@
if (activeInput != 0) {
sp<AudioInputDescriptor> activeDesc = mInputs.valueFor(activeInput);
if (activeDesc->getModuleHandle() == txSourceDeviceDesc->getModuleHandle()) {
- audio_session_t activeSession = activeDesc->mSessions.itemAt(0);
+ //FIXME: consider all active sessions
+ AudioSessionCollection activeSessions = activeDesc->getActiveAudioSessions();
+ audio_session_t activeSession = activeSessions.keyAt(0);
stopInput(activeInput, activeSession);
releaseInput(activeInput, activeSession);
}
@@ -1329,7 +1331,6 @@
audio_devices_t device;
// handle legacy remote submix case where the address was not always specified
String8 address = String8("");
- bool isSoundTrigger = false;
audio_source_t inputSource = attr->source;
audio_source_t halInputSource;
AudioMix *policyMix = NULL;
@@ -1385,16 +1386,44 @@
*inputType = API_INPUT_LEGACY;
}
- if (inputSource == AUDIO_SOURCE_HOTWORD) {
- ssize_t index = mSoundTriggerSessions.indexOfKey(session);
- if (index >= 0) {
- *input = mSoundTriggerSessions.valueFor(session);
- isSoundTrigger = true;
- flags = (audio_input_flags_t)(flags | AUDIO_INPUT_FLAG_HW_HOTWORD);
- ALOGV("SoundTrigger capture on session %d input %d", session, *input);
- } else {
- halInputSource = AUDIO_SOURCE_VOICE_RECOGNITION;
- }
+ }
+
+ *input = getInputForDevice(device, address, session, uid, inputSource,
+ samplingRate, format, channelMask, flags,
+ policyMix);
+ if (*input == AUDIO_IO_HANDLE_NONE) {
+ mInputRoutes.removeRoute(session);
+ return INVALID_OPERATION;
+ }
+ ALOGV("getInputForAttr() returns input type = %d", *inputType);
+ return NO_ERROR;
+}
+
+
+audio_io_handle_t AudioPolicyManager::getInputForDevice(audio_devices_t device,
+ String8 address,
+ audio_session_t session,
+ uid_t uid,
+ audio_source_t inputSource,
+ uint32_t samplingRate,
+ audio_format_t format,
+ audio_channel_mask_t channelMask,
+ audio_input_flags_t flags,
+ AudioMix *policyMix)
+{
+ audio_io_handle_t input = AUDIO_IO_HANDLE_NONE;
+ audio_source_t halInputSource = inputSource;
+ bool isSoundTrigger = false;
+
+ if (inputSource == AUDIO_SOURCE_HOTWORD) {
+ ssize_t index = mSoundTriggerSessions.indexOfKey(session);
+ if (index >= 0) {
+ input = mSoundTriggerSessions.valueFor(session);
+ isSoundTrigger = true;
+ flags = (audio_input_flags_t)(flags | AUDIO_INPUT_FLAG_HW_HOTWORD);
+ ALOGV("SoundTrigger capture on session %d input %d", session, input);
+ } else {
+ halInputSource = AUDIO_SOURCE_VOICE_RECOGNITION;
}
}
@@ -1414,25 +1443,62 @@
} else if (profileFlags != AUDIO_INPUT_FLAG_NONE) {
profileFlags = AUDIO_INPUT_FLAG_NONE; // retry
} else { // fail
- ALOGW("getInputForAttr() could not find profile for device 0x%X, samplingRate %u,"
- "format %#x, channelMask 0x%X, flags %#x",
+ ALOGW("getInputForDevice() could not find profile for device 0x%X,"
+ "samplingRate %u, format %#x, channelMask 0x%X, flags %#x",
device, samplingRate, format, channelMask, flags);
- return BAD_VALUE;
+ return input;
}
}
if (profile->getModuleHandle() == 0) {
ALOGE("getInputForAttr(): HW module %s not opened", profile->getModuleName());
- return NO_INIT;
+ return input;
}
+ sp<AudioSession> audioSession = new AudioSession(session,
+ inputSource,
+ format,
+ samplingRate,
+ channelMask,
+ flags,
+ uid,
+ isSoundTrigger);
+
+// TODO enable input reuse
+#if 0
+ // reuse an open input if possible
+ for (size_t i = 0; i < mInputs.size(); i++) {
+ sp<AudioInputDescriptor> desc = mInputs.valueAt(i);
+ // reuse input if it shares the same profile and same sound trigger attribute
+ if (profile == desc->mProfile &&
+ isSoundTrigger == desc->isSoundTrigger()) {
+
+ sp<AudioSession> as = desc->getAudioSession(session);
+ if (as != 0) {
+ // do not allow unmatching properties on same session
+ if (as->matches(audioSession)) {
+ as->changeOpenCount(1);
+ } else {
+ ALOGW("getInputForDevice() record with different attributes"
+ " exists for session %d", session);
+ return input;
+ }
+ } else {
+ desc->addAudioSession(session, audioSession);
+ }
+ ALOGV("getInputForDevice() reusing input %d", mInputs.keyAt(i));
+ return mInputs.keyAt(i);
+ }
+ }
+#endif
+
audio_config_t config = AUDIO_CONFIG_INITIALIZER;
config.sample_rate = profileSamplingRate;
config.channel_mask = profileChannelMask;
config.format = profileFormat;
status_t status = mpClientInterface->openInput(profile->getModuleHandle(),
- input,
+ &input,
&config,
&device,
address,
@@ -1440,37 +1506,31 @@
profileFlags);
// only accept input with the exact requested set of parameters
- if (status != NO_ERROR || *input == AUDIO_IO_HANDLE_NONE ||
+ if (status != NO_ERROR || input == AUDIO_IO_HANDLE_NONE ||
(profileSamplingRate != config.sample_rate) ||
(profileFormat != config.format) ||
(profileChannelMask != config.channel_mask)) {
- ALOGW("getInputForAttr() failed opening input: samplingRate %d, format %d,"
- " channelMask %x",
+ ALOGW("getInputForAttr() failed opening input: samplingRate %d"
+ ", format %d, channelMask %x",
samplingRate, format, channelMask);
- if (*input != AUDIO_IO_HANDLE_NONE) {
- mpClientInterface->closeInput(*input);
+ if (input != AUDIO_IO_HANDLE_NONE) {
+ mpClientInterface->closeInput(input);
}
- return BAD_VALUE;
+ return AUDIO_IO_HANDLE_NONE;
}
sp<AudioInputDescriptor> inputDesc = new AudioInputDescriptor(profile);
- inputDesc->mInputSource = inputSource;
- inputDesc->mRefCount = 0;
inputDesc->mSamplingRate = profileSamplingRate;
inputDesc->mFormat = profileFormat;
inputDesc->mChannelMask = profileChannelMask;
inputDesc->mDevice = device;
- inputDesc->mSessions.add(session);
- inputDesc->mIsSoundTrigger = isSoundTrigger;
inputDesc->mPolicyMix = policyMix;
- inputDesc->changeOpenRefCount(1);
+ inputDesc->addAudioSession(session, audioSession);
- ALOGV("getInputForAttr() returns input type = %d", *inputType);
-
- addInput(*input, inputDesc);
+ addInput(input, inputDesc);
mpClientInterface->onAudioPortListUpdate();
- return NO_ERROR;
+ return input;
}
status_t AudioPolicyManager::startInput(audio_io_handle_t input,
@@ -1484,8 +1544,8 @@
}
sp<AudioInputDescriptor> inputDesc = mInputs.valueAt(index);
- index = inputDesc->mSessions.indexOf(session);
- if (index < 0) {
+ sp<AudioSession> audioSession = inputDesc->getAudioSession(session);
+ if (audioSession == 0) {
ALOGW("startInput() unknown session %d on input %d", session, input);
return BAD_VALUE;
}
@@ -1500,11 +1560,14 @@
// If the already active input uses AUDIO_SOURCE_HOTWORD then it is closed,
// otherwise the active input continues and the new input cannot be started.
sp<AudioInputDescriptor> activeDesc = mInputs.valueFor(activeInput);
- if ((activeDesc->mInputSource == AUDIO_SOURCE_HOTWORD) &&
+ if ((activeDesc->inputSource() == AUDIO_SOURCE_HOTWORD) &&
!activeDesc->hasPreemptedSession(session)) {
ALOGW("startInput(%d) preempting low-priority input %d", input, activeInput);
- audio_session_t activeSession = activeDesc->mSessions.itemAt(0);
- SortedVector<audio_session_t> sessions = activeDesc->getPreemptedSessions();
+ //FIXME: consider all active sessions
+ AudioSessionCollection activeSessions = activeDesc->getActiveAudioSessions();
+ audio_session_t activeSession = activeSessions.keyAt(0);
+ SortedVector<audio_session_t> sessions =
+ activeDesc->getPreemptedSessions();
sessions.add(activeSession);
inputDesc->setPreemptedSessions(sessions);
stopInput(activeInput, activeSession);
@@ -1528,7 +1591,7 @@
// Routing?
mInputRoutes.incRouteActivity(session);
- if (inputDesc->mRefCount == 0 || mInputRoutes.hasRouteChanged(session)) {
+ if (!inputDesc->isActive() || mInputRoutes.hasRouteChanged(session)) {
// if input maps to a dynamic policy with an activity listener, notify of state change
if ((inputDesc->mPolicyMix != NULL)
&& ((inputDesc->mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0)) {
@@ -1559,9 +1622,9 @@
}
}
- ALOGV("AudioPolicyManager::startInput() input source = %d", inputDesc->mInputSource);
+ ALOGV("AudioPolicyManager::startInput() input source = %d", audioSession->inputSource());
- inputDesc->mRefCount++;
+ audioSession->changeActiveCount(1);
return NO_ERROR;
}
@@ -1576,23 +1639,23 @@
}
sp<AudioInputDescriptor> inputDesc = mInputs.valueAt(index);
- index = inputDesc->mSessions.indexOf(session);
+ sp<AudioSession> audioSession = inputDesc->getAudioSession(session);
if (index < 0) {
ALOGW("stopInput() unknown session %d on input %d", session, input);
return BAD_VALUE;
}
- if (inputDesc->mRefCount == 0) {
+ if (audioSession->activeCount() == 0) {
ALOGW("stopInput() input %d already stopped", input);
return INVALID_OPERATION;
}
- inputDesc->mRefCount--;
+ audioSession->changeActiveCount(-1);
// Routing?
mInputRoutes.decRouteActivity(session);
- if (inputDesc->mRefCount == 0) {
+ if (!inputDesc->isActive()) {
// if input maps to a dynamic policy with an activity listener, notify of state change
if ((inputDesc->mPolicyMix != NULL)
&& ((inputDesc->mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0)) {
@@ -1642,17 +1705,22 @@
sp<AudioInputDescriptor> inputDesc = mInputs.valueAt(index);
ALOG_ASSERT(inputDesc != 0);
- index = inputDesc->mSessions.indexOf(session);
+ sp<AudioSession> audioSession = inputDesc->getAudioSession(session);
if (index < 0) {
ALOGW("releaseInput() unknown session %d on input %d", session, input);
return;
}
- inputDesc->mSessions.remove(session);
- if (inputDesc->getOpenRefCount() == 0) {
- ALOGW("releaseInput() invalid open ref count %d", inputDesc->getOpenRefCount());
+
+ if (audioSession->openCount() == 0) {
+ ALOGW("releaseInput() invalid open count %d on session %d",
+ audioSession->openCount(), session);
return;
}
- inputDesc->changeOpenRefCount(-1);
+
+ if (audioSession->changeOpenCount(-1) == 0) {
+ inputDesc->removeAudioSession(session);
+ }
+
if (inputDesc->getOpenRefCount() > 0) {
ALOGV("releaseInput() exit > 0");
return;
@@ -1867,23 +1935,9 @@
{
for (size_t i = 0; i < mInputs.size(); i++) {
const sp<AudioInputDescriptor> inputDescriptor = mInputs.valueAt(i);
- if (inputDescriptor->mRefCount == 0) {
- continue;
- }
- if (inputDescriptor->mInputSource == (int)source) {
+ if (inputDescriptor->isSourceActive(source)) {
return true;
}
- // AUDIO_SOURCE_HOTWORD is equivalent to AUDIO_SOURCE_VOICE_RECOGNITION only if it
- // corresponds to an active capture triggered by a hardware hotword recognition
- if ((source == AUDIO_SOURCE_VOICE_RECOGNITION) &&
- (inputDescriptor->mInputSource == AUDIO_SOURCE_HOTWORD)) {
- // FIXME: we should not assume that the first session is the active one and keep
- // activity count per session. Same in startInput().
- ssize_t index = mSoundTriggerSessions.indexOfKey(inputDescriptor->mSessions.itemAt(0));
- if (index >= 0) {
- return true;
- }
- }
}
return false;
}
@@ -2037,8 +2091,8 @@
write(fd, result.string(), result.size());
- mAvailableOutputDevices.dump(fd, String8("output"));
- mAvailableInputDevices.dump(fd, String8("input"));
+ mAvailableOutputDevices.dump(fd, String8("Available output"));
+ mAvailableInputDevices.dump(fd, String8("Available input"));
mHwModules.dump(fd);
mOutputs.dump(fd);
mInputs.dump(fd);
@@ -2663,7 +2717,7 @@
SortedVector<audio_io_handle_t> inputsToClose;
for (size_t i = 0; i < mInputs.size(); i++) {
sp<AudioInputDescriptor> inputDesc = mInputs.valueAt(i);
- if (affectedSources.indexOf(inputDesc->mInputSource) >= 0) {
+ if (affectedSources.indexOf(inputDesc->inputSource()) >= 0) {
inputsToClose.add(inputDesc->mIoHandle);
}
}
@@ -3026,7 +3080,6 @@
}
sp<AudioInputDescriptor> inputDesc = new AudioInputDescriptor(inProfile);
- inputDesc->mInputSource = AUDIO_SOURCE_MIC;
inputDesc->mDevice = profileType;
// find the address
@@ -3449,55 +3502,14 @@
mpClientInterface->setParameters(output, String8(param));
free(param);
}
-
- // Here is where we step through and resolve any "dynamic" fields
- String8 reply;
- char *value;
- if (profile->mSamplingRates[0] == 0) {
- reply = mpClientInterface->getParameters(output,
- String8(AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES));
- ALOGV("checkOutputsForDevice() supported sampling rates %s",
- reply.string());
- value = strpbrk((char *)reply.string(), "=");
- if (value != NULL) {
- profile->setSupportedSamplingRates(samplingRatesFromString(value + 1));
- }
- }
- if (profile->mFormats[0] == AUDIO_FORMAT_DEFAULT) {
- reply = mpClientInterface->getParameters(output,
- String8(AUDIO_PARAMETER_STREAM_SUP_FORMATS));
- ALOGV("checkOutputsForDevice() supported formats %s",
- reply.string());
- value = strpbrk((char *)reply.string(), "=");
- if (value != NULL) {
- profile->setSupportedFormats(formatsFromString(value + 1));
- }
- }
- if (profile->mChannelMasks[0] == 0) {
- reply = mpClientInterface->getParameters(output,
- String8(AUDIO_PARAMETER_STREAM_SUP_CHANNELS));
- ALOGV("checkOutputsForDevice() supported channel masks %s",
- reply.string());
- value = strpbrk((char *)reply.string(), "=");
- if (value != NULL) {
- profile->setSupportedChannelMasks(outputChannelMasksFromString(value + 1));
- }
- }
- if (((profile->mSamplingRates[0] == 0) &&
- (profile->mSamplingRates.size() < 2)) ||
- ((profile->mFormats[0] == AUDIO_FORMAT_DEFAULT) &&
- (profile->mFormats.size() < 2)) ||
- ((profile->mChannelMasks[0] == 0) &&
- (profile->mChannelMasks.size() < 2))) {
+ updateAudioProfiles(output, profile->getAudioProfiles());
+ if (!profile->hasValidAudioProfile()) {
ALOGW("checkOutputsForDevice() missing param");
mpClientInterface->closeOutput(output);
output = AUDIO_IO_HANDLE_NONE;
- } else if (profile->mSamplingRates[0] == 0 || profile->mFormats[0] == 0 ||
- profile->mChannelMasks[0] == 0) {
+ } else if (profile->hasDynamicAudioProfile()) {
mpClientInterface->closeOutput(output);
- config.sample_rate = profile->pickSamplingRate();
- config.channel_mask = profile->pickChannelMask();
- config.format = profile->pickFormat();
+ profile->pickAudioProfile(config.sample_rate, config.channel_mask, config.format);
config.offload_info.sample_rate = config.sample_rate;
config.offload_info.channel_mask = config.channel_mask;
config.offload_info.format = config.format;
@@ -3621,18 +3633,7 @@
if (profile->supportDevice(device)) {
ALOGV("checkOutputsForDevice(): "
"clearing direct output profile %zu on module %zu", j, i);
- if (profile->mSamplingRates[0] == 0) {
- profile->mSamplingRates.clear();
- profile->mSamplingRates.add(0);
- }
- if (profile->mFormats[0] == AUDIO_FORMAT_DEFAULT) {
- profile->mFormats.clear();
- profile->mFormats.add(AUDIO_FORMAT_DEFAULT);
- }
- if (profile->mChannelMasks[0] == 0) {
- profile->mChannelMasks.clear();
- profile->mChannelMasks.add(0);
- }
+ profile->clearAudioProfiles();
}
}
}
@@ -3738,42 +3739,8 @@
mpClientInterface->setParameters(input, String8(param));
free(param);
}
-
- // Here is where we step through and resolve any "dynamic" fields
- String8 reply;
- char *value;
- if (profile->mSamplingRates[0] == 0) {
- reply = mpClientInterface->getParameters(input,
- String8(AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES));
- ALOGV("checkInputsForDevice() direct input sup sampling rates %s",
- reply.string());
- value = strpbrk((char *)reply.string(), "=");
- if (value != NULL) {
- profile->setSupportedSamplingRates(samplingRatesFromString(value + 1));
- }
- }
- if (profile->mFormats[0] == AUDIO_FORMAT_DEFAULT) {
- reply = mpClientInterface->getParameters(input,
- String8(AUDIO_PARAMETER_STREAM_SUP_FORMATS));
- ALOGV("checkInputsForDevice() direct input sup formats %s", reply.string());
- value = strpbrk((char *)reply.string(), "=");
- if (value != NULL) {
- profile->setSupportedFormats(formatsFromString(value + 1));
- }
- }
- if (profile->mChannelMasks[0] == 0) {
- reply = mpClientInterface->getParameters(input,
- String8(AUDIO_PARAMETER_STREAM_SUP_CHANNELS));
- ALOGV("checkInputsForDevice() direct input sup channel masks %s",
- reply.string());
- value = strpbrk((char *)reply.string(), "=");
- if (value != NULL) {
- profile->setSupportedChannelMasks(inputChannelMasksFromString(value + 1));
- }
- }
- if (((profile->mSamplingRates[0] == 0) && (profile->mSamplingRates.size() < 2)) ||
- ((profile->mFormats[0] == 0) && (profile->mFormats.size() < 2)) ||
- ((profile->mChannelMasks[0] == 0) && (profile->mChannelMasks.size() < 2))) {
+ updateAudioProfiles(input, profile->getAudioProfiles());
+ if (!profile->hasValidAudioProfile()) {
ALOGW("checkInputsForDevice() direct input missing param");
mpClientInterface->closeInput(input);
input = AUDIO_IO_HANDLE_NONE;
@@ -3824,18 +3791,7 @@
if (profile->supportDevice(device)) {
ALOGV("checkInputsForDevice(): clearing direct input profile %zu on module %zu",
profile_index, module_index);
- if (profile->mSamplingRates[0] == 0) {
- profile->mSamplingRates.clear();
- profile->mSamplingRates.add(0);
- }
- if (profile->mFormats[0] == AUDIO_FORMAT_DEFAULT) {
- profile->mFormats.clear();
- profile->mFormats.add(AUDIO_FORMAT_DEFAULT);
- }
- if (profile->mChannelMasks[0] == 0) {
- profile->mChannelMasks.clear();
- profile->mChannelMasks.add(0);
- }
+ profile->clearAudioProfiles();
}
}
}
@@ -4171,7 +4127,7 @@
}
}
- audio_devices_t device = getDeviceAndMixForInputSource(inputDesc->mInputSource);
+ audio_devices_t device = getDeviceAndMixForInputSource(inputDesc->inputSource());
return device;
}
@@ -4583,7 +4539,7 @@
// AUDIO_SOURCE_HOTWORD is for internal use only:
// handled as AUDIO_SOURCE_VOICE_RECOGNITION by the audio HAL
if (patch.sinks[0].ext.mix.usecase.source == AUDIO_SOURCE_HOTWORD &&
- !inputDesc->mIsSoundTrigger) {
+ !inputDesc->isSoundTrigger()) {
patch.sinks[0].ext.mix.usecase.source = AUDIO_SOURCE_VOICE_RECOGNITION;
}
patch.num_sinks = 1;
@@ -5095,5 +5051,51 @@
}
}
+void AudioPolicyManager::updateAudioProfiles(audio_io_handle_t ioHandle,
+ AudioProfileVector &profiles)
+{
+ String8 reply;
+ char *value;
+ // Format MUST be checked first to update the list of AudioProfile
+ if (profiles.hasDynamicFormat()) {
+ reply = mpClientInterface->getParameters(ioHandle,
+ String8(AUDIO_PARAMETER_STREAM_SUP_FORMATS));
+ ALOGV("%s: supported formats %s", __FUNCTION__, reply.string());
+ value = strpbrk((char *)reply.string(), "=");
+ if (value == NULL) {
+ ALOGE("%s: failed to retrieve format, bailing out", __FUNCTION__);
+ return;
+ }
+ profiles.setFormats(formatsFromString(value + 1));
+ }
+ const FormatVector &supportedFormats = profiles.getSupportedFormats();
+
+ for(size_t formatIndex = 0; formatIndex < supportedFormats.size(); formatIndex++) {
+ audio_format_t format = supportedFormats[formatIndex];
+ AudioParameter requestedParameters;
+ requestedParameters.addInt(String8(AUDIO_PARAMETER_STREAM_FORMAT), format);
+
+ if (profiles.hasDynamicRateFor(format)) {
+ reply = mpClientInterface->getParameters(ioHandle,
+ requestedParameters.toString() + ";" +
+ AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES);
+ ALOGV("%s: supported sampling rates %s", __FUNCTION__, reply.string());
+ value = strpbrk((char *)reply.string(), "=");
+ if (value != NULL) {
+ profiles.setSampleRatesFor(samplingRatesFromString(value + 1), format);
+ }
+ }
+ if (profiles.hasDynamicChannelsFor(format)) {
+ reply = mpClientInterface->getParameters(ioHandle,
+ requestedParameters.toString() + ";" +
+ AUDIO_PARAMETER_STREAM_SUP_CHANNELS);
+ ALOGV("%s: supported channel masks %s", __FUNCTION__, reply.string());
+ value = strpbrk((char *)reply.string(), "=");
+ if (value != NULL) {
+ profiles.setChannelsFor(channelMasksFromString(value + 1), format);
+ }
+ }
+ }
+}
}; // namespace android
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index bb71090..59163ca 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -587,6 +587,9 @@
// Audio Policy Engine Interface.
AudioPolicyManagerInterface *mEngine;
private:
+ // If any, resolve any "dynamic" fields of an Audio Profiles collection
+ void updateAudioProfiles(audio_io_handle_t ioHandle, AudioProfileVector &profiles);
+
// updates device caching and output for streams that can influence the
// routing of notifications
void handleNotificationRoutingForStream(audio_stream_type_t stream);
@@ -610,6 +613,18 @@
audio_channel_mask_t channelMask,
audio_output_flags_t flags,
const audio_offload_info_t *offloadInfo);
+ // internal method to return the input handle for the given device and format
+ audio_io_handle_t getInputForDevice(audio_devices_t device,
+ String8 address,
+ audio_session_t session,
+ uid_t uid,
+ audio_source_t inputSource,
+ uint32_t samplingRate,
+ audio_format_t format,
+ audio_channel_mask_t channelMask,
+ audio_input_flags_t flags,
+ AudioMix *policyMix);
+
// internal function to derive a stream type value from audio attributes
audio_stream_type_t streamTypefromAttributesInt(const audio_attributes_t *attr);
// event is one of STARTING_OUTPUT, STARTING_BEACON, STOPPING_OUTPUT, STOPPING_BEACON