audio policy: add open and active count for IO profiles
Remove the hardcoded limit of one open output stream per IO profile
and add a max open count per IO profile.
Same thing for maximum number of active input streams per IO profile.
Now both the maximum number of opened streams and active streams for
a given profile is stored in that profile.
For now only defaults are set corresponding to legacy behavior,
but these values will be loaded form the audio policy configuration file.
Test: AudioTrack and AudioRecord CTS tests
Change-Id: I5ebcc7f8a06b3f0a52815d241c561bb65e036026
diff --git a/services/audiopolicy/common/managerdefinitions/include/IOProfile.h b/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
index ec04ef7..118f0d2 100644
--- a/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
+++ b/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
@@ -34,7 +34,11 @@
{
public:
IOProfile(const String8 &name, audio_port_role_t role)
- : AudioPort(name, AUDIO_PORT_TYPE_MIX, role) {}
+ : AudioPort(name, AUDIO_PORT_TYPE_MIX, role),
+ maxOpenCount((role == AUDIO_PORT_ROLE_SOURCE) ? 1 : 0),
+ curOpenCount(0),
+ maxActiveCount(1),
+ curActiveCount(0) {}
// For a Profile aka MixPort, tag name and name are equivalent.
virtual const String8 getTagName() const { return getName(); }
@@ -103,6 +107,34 @@
const DeviceVector &getSupportedDevices() const { return mSupportedDevices; }
+ bool canOpenNewIo() {
+ if (maxOpenCount == 0 || curOpenCount < maxOpenCount) {
+ return true;
+ }
+ return false;
+ }
+
+ bool canStartNewIo() {
+ if (maxActiveCount == 0 || curActiveCount < maxActiveCount) {
+ return true;
+ }
+ return false;
+ }
+
+ // Maximum number of input or output streams that can be simultaneously opened for this profile.
+ // By convention 0 means no limit. To respect legacy behavior, initialized to 1 for output
+ // profiles and 0 for input profiles
+ uint32_t maxOpenCount;
+ // Number of streams currently opened for this profile.
+ uint32_t curOpenCount;
+ // Maximum number of input or output streams that can be simultaneously active for this profile.
+ // By convention 0 means no limit. To respect legacy behavior, initialized to 0 for output
+ // profiles and 1 for input profiles
+ uint32_t maxActiveCount;
+ // Number of streams currently active for this profile. This is not the number of active clients
+ // (AudioTrack or AudioRecord) but the number of active HAL streams.
+ uint32_t curActiveCount;
+
private:
DeviceVector mSupportedDevices; // supported devices: this input/output can be routed from/to
};
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
index 624e688..737872d 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
@@ -236,6 +236,7 @@
mFormat = lConfig.format;
mId = AudioPort::getNextUniqueId();
mIoHandle = *input;
+ mProfile->curOpenCount++;
}
return status;
@@ -246,6 +247,10 @@
{
if (mIoHandle != AUDIO_IO_HANDLE_NONE) {
mClientInterface->closeInput(mIoHandle);
+ LOG_ALWAYS_FATAL_IF(mProfile->curOpenCount < 1, "%s profile open count %u",
+ __FUNCTION__, mProfile->curOpenCount);
+ mProfile->curOpenCount--;
+ mIoHandle = AUDIO_IO_HANDLE_NONE;
}
}
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
index f96c5bc..be5a1c1 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
@@ -444,6 +444,7 @@
mFormat = lConfig.format;
mId = AudioPort::getNextUniqueId();
mIoHandle = *output;
+ mProfile->curOpenCount++;
}
return status;
@@ -458,6 +459,11 @@
mClientInterface->setParameters(mIoHandle, param.toString());
mClientInterface->closeOutput(mIoHandle);
+
+ LOG_ALWAYS_FATAL_IF(mProfile->curOpenCount < 1, "%s profile open count %u",
+ __FUNCTION__, mProfile->curOpenCount);
+ mProfile->curOpenCount--;
+ mIoHandle = AUDIO_IO_HANDLE_NONE;
}
}
diff --git a/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp b/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp
index 74ef4ec..fc89672 100644
--- a/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp
@@ -122,6 +122,16 @@
result.append("\n");
write(fd, result.string(), result.size());
mSupportedDevices.dump(fd, String8("Supported"), 4, false);
+
+ result.clear();
+ snprintf(buffer, SIZE, "\n - maxOpenCount: %u - curOpenCount: %u\n",
+ maxOpenCount, curOpenCount);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " - maxActiveCount: %u - curActiveCount: %u\n",
+ maxActiveCount, curActiveCount);
+ result.append(buffer);
+
+ write(fd, result.string(), result.size());
}
void IOProfile::log()
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 7dd1096..2096dda 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -926,37 +926,29 @@
}
if (profile != 0) {
- sp<SwAudioOutputDescriptor> outputDesc = NULL;
-
for (size_t i = 0; i < mOutputs.size(); i++) {
sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
if (!desc->isDuplicated() && (profile == desc->mProfile)) {
- outputDesc = desc;
// reuse direct output if currently open by the same client
// and configured with same parameters
- if ((config->sample_rate == outputDesc->mSamplingRate) &&
- audio_formats_match(config->format, outputDesc->mFormat) &&
- (config->channel_mask == outputDesc->mChannelMask)) {
- if (session == outputDesc->mDirectClientSession) {
- outputDesc->mDirectOpenCount++;
- ALOGV("getOutputForDevice() reusing direct output %d for session %d",
- mOutputs.keyAt(i), session);
- return mOutputs.keyAt(i);
- } else {
- ALOGV("getOutputForDevice() do not reuse direct output because"
- "current client (%d) is not the same as requesting client (%d)",
- outputDesc->mDirectClientSession, session);
- goto non_direct_output;
- }
+ if ((config->sample_rate == desc->mSamplingRate) &&
+ audio_formats_match(config->format, desc->mFormat) &&
+ (config->channel_mask == desc->mChannelMask) &&
+ (session == desc->mDirectClientSession)) {
+ desc->mDirectOpenCount++;
+ ALOGV("getOutputForDevice() reusing direct output %d for session %d",
+ mOutputs.keyAt(i), session);
+ return mOutputs.keyAt(i);
}
}
}
- // close direct output if currently open and configured with different parameters
- if (outputDesc != NULL) {
- closeOutput(outputDesc->mIoHandle);
+
+ if (!profile->canOpenNewIo()) {
+ goto non_direct_output;
}
- outputDesc = new SwAudioOutputDescriptor(profile, mpClientInterface);
+ sp<SwAudioOutputDescriptor> outputDesc =
+ new SwAudioOutputDescriptor(profile, mpClientInterface);
status = outputDesc->open(config, device, String8(""), stream, flags, &output);
// only accept an output with the requested parameters
@@ -1114,6 +1106,13 @@
sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueAt(index);
+ if (!outputDesc->isActive()) {
+ if (!outputDesc->mProfile->canStartNewIo()) {
+ return INVALID_OPERATION;
+ }
+ outputDesc->mProfile->curActiveCount++;
+ }
+
// Routing?
mOutputRoutes.incRouteActivity(session);
@@ -1141,6 +1140,12 @@
if (status != NO_ERROR) {
mOutputRoutes.decRouteActivity(session);
+ if (!outputDesc->isActive()) {
+ LOG_ALWAYS_FATAL_IF(outputDesc->mProfile->curActiveCount < 1,
+ "%s invalid profile active count %u",
+ __FUNCTION__, outputDesc->mProfile->curActiveCount);
+ outputDesc->mProfile->curActiveCount--;
+ }
return status;
}
// Automatically enable the remote submix input when output is started on a re routing mix
@@ -1329,7 +1334,15 @@
}
}
- return stopSource(outputDesc, stream, forceDeviceUpdate);
+ status_t status = stopSource(outputDesc, stream, forceDeviceUpdate);
+
+ if (status == NO_ERROR && !outputDesc->isActive()) {
+ LOG_ALWAYS_FATAL_IF(outputDesc->mProfile->curActiveCount < 1,
+ "%s invalid profile active count %u",
+ __FUNCTION__, outputDesc->mProfile->curActiveCount);
+ outputDesc->mProfile->curActiveCount--;
+ }
+ return status;
}
status_t AudioPolicyManager::stopSource(const sp<AudioOutputDescriptor>& outputDesc,
@@ -1715,6 +1728,10 @@
}
#endif
+ if (!profile->canOpenNewIo()) {
+ return AUDIO_IO_HANDLE_NONE;
+ }
+
sp<AudioInputDescriptor> inputDesc = new AudioInputDescriptor(profile, mpClientInterface);
audio_config_t lConfig = AUDIO_CONFIG_INITIALIZER;
@@ -1952,6 +1969,13 @@
setInputDevice(input, device, true /* force */);
if (inputDesc->getAudioSessionCount(true/*activeOnly*/) == 1) {
+ if (!inputDesc->mProfile->canStartNewIo()) {
+ mInputRoutes.decRouteActivity(session);
+ audioSession->changeActiveCount(-1);
+ return INVALID_OPERATION;
+ }
+ inputDesc->mProfile->curActiveCount++;
+
// 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)) {
@@ -2021,6 +2045,11 @@
if (inputDesc->isActive()) {
setInputDevice(input, getNewInputDevice(inputDesc), false /* force */);
} else {
+ LOG_ALWAYS_FATAL_IF(inputDesc->mProfile->curActiveCount < 1,
+ "%s invalid profile active count %u",
+ __FUNCTION__, inputDesc->mProfile->curActiveCount);
+ inputDesc->mProfile->curActiveCount--;
+
// 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)) {
@@ -3578,6 +3607,12 @@
{
const sp<IOProfile> outProfile = mHwModules[i]->mOutputProfiles[j];
+ if (!outProfile->canOpenNewIo()) {
+ ALOGE("Invalid Output profile max open count %u for profile %s",
+ outProfile->maxOpenCount, outProfile->getTagName().c_str());
+ continue;
+ }
+
if (!outProfile->hasSupportedDevices()) {
ALOGW("Output profile contains no device on module %s", mHwModules[i]->getName());
continue;
@@ -3641,6 +3676,12 @@
{
const sp<IOProfile> inProfile = mHwModules[i]->mInputProfiles[j];
+ if (!inProfile->canOpenNewIo()) {
+ ALOGE("Invalid Input profile max open count %u for profile %s",
+ inProfile->maxOpenCount, inProfile->getTagName().c_str());
+ continue;
+ }
+
if (!inProfile->hasSupportedDevices()) {
ALOGW("Input profile contains no device on module %s", mHwModules[i]->getName());
continue;
@@ -3848,6 +3889,12 @@
continue;
}
+ if (!profile->canOpenNewIo()) {
+ ALOGW("Max Output number %u already opened for this profile %s",
+ profile->maxOpenCount, profile->getTagName().c_str());
+ continue;
+ }
+
ALOGV("opening output for device %08x with params %s profile %p name %s",
device, address.string(), profile.get(), profile->getName().string());
desc = new SwAudioOutputDescriptor(profile, mpClientInterface);
@@ -4053,6 +4100,7 @@
for (ssize_t profile_index = 0; profile_index < (ssize_t)profiles.size(); profile_index++) {
sp<IOProfile> profile = profiles[profile_index];
+
// nothing to do if one input is already opened for this profile
size_t input_index;
for (input_index = 0; input_index < mInputs.size(); input_index++) {
@@ -4068,6 +4116,12 @@
continue;
}
+ if (!profile->canOpenNewIo()) {
+ ALOGW("Max Input number %u already opened for this profile %s",
+ profile->maxOpenCount, profile->getTagName().c_str());
+ continue;
+ }
+
desc = new AudioInputDescriptor(profile, mpClientInterface);
audio_io_handle_t input = AUDIO_IO_HANDLE_NONE;
status_t status = desc->open(nullptr,