audiopolicy: refactor playback activity ref counting
Playback activity ref couting is now based on active state
of PlaybackClientDescriptor.
The active reference count per stream on each output is still
used because it provides a simple implementation for duplicated output.
Test: CTS tests for AudioTrack and Routing
Test: manual audio smoke test
Change-Id: Ifadb1d24131581461aace14a5b25e7c7582c57cb
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
index 4cf16a0..27b1c93 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
@@ -59,7 +59,10 @@
audio_devices_t device,
uint32_t delayMs,
bool force);
- virtual void changeRefCount(audio_stream_type_t stream, int delta);
+ virtual void changeStreamActiveCount(audio_stream_type_t stream, int delta);
+ uint32_t streamActiveCount(audio_stream_type_t stream) const
+ { return mActiveCount[stream]; }
+ void setClientActive(const sp<TrackClientDescriptor>& client, bool active);
bool isActive(uint32_t inPastMs = 0) const;
bool isStreamActive(audio_stream_type_t stream,
@@ -84,15 +87,17 @@
sp<AudioPort> mPort;
audio_devices_t mDevice; // current device this output is routed to
- uint32_t mRefCount[AUDIO_STREAM_CNT]; // number of streams of each type using this output
nsecs_t mStopTime[AUDIO_STREAM_CNT];
float mCurVolume[AUDIO_STREAM_CNT]; // current stream volume in dB
int mMuteCount[AUDIO_STREAM_CNT]; // mute request counter
bool mStrategyMutedByDevice[NUM_STRATEGIES]; // strategies muted because of incompatible
// device selection. See checkDeviceMuteStrategies()
AudioPolicyClientInterface *mClientInterface;
+ AudioMix *mPolicyMix; // non NULL when used by a dynamic policy
protected:
+ uint32_t mActiveCount[AUDIO_STREAM_CNT]; // number of streams of each type active on this output
+ uint32_t mGlobalActiveCount; // non-client-specific active count
audio_patch_handle_t mPatchHandle;
audio_port_handle_t mId;
TrackClientMap mClients;
@@ -116,7 +121,7 @@
virtual bool isFixedVolume(audio_devices_t device);
virtual sp<AudioOutputDescriptor> subOutput1() { return mOutput1; }
virtual sp<AudioOutputDescriptor> subOutput2() { return mOutput2; }
- virtual void changeRefCount(audio_stream_type_t stream, int delta);
+ virtual void changeStreamActiveCount(audio_stream_type_t stream, int delta);
virtual bool setVolume(float volume,
audio_stream_type_t stream,
audio_devices_t device,
@@ -134,10 +139,10 @@
audio_output_flags_t flags,
audio_io_handle_t *output);
// Called when a stream is about to be started
- // Note: called before changeRefCount(1);
+ // Note: called before setClientActive(true);
status_t start();
// Called after a stream is stopped.
- // Note: called after changeRefCount(-1);
+ // Note: called after setClientActive(false);
void stop();
void close();
status_t openDuplicating(const sp<SwAudioOutputDescriptor>& output1,
@@ -148,12 +153,10 @@
audio_io_handle_t mIoHandle; // output handle
uint32_t mLatency; //
audio_output_flags_t mFlags; //
- AudioMix *mPolicyMix; // non NULL when used by a dynamic policy
sp<SwAudioOutputDescriptor> mOutput1; // used by duplicated outputs: first output
sp<SwAudioOutputDescriptor> mOutput2; // used by duplicated outputs: second output
uint32_t mDirectOpenCount; // number of clients using this output (direct outputs only)
audio_session_t mDirectClientSession; // session id of the direct output client
- uint32_t mGlobalRefCount; // non-stream-specific ref count
};
// Audio output driven by an input device directly.
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
index a39ac6d..b6ff6ea 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
@@ -34,12 +34,12 @@
AudioOutputDescriptor::AudioOutputDescriptor(const sp<AudioPort>& port,
AudioPolicyClientInterface *clientInterface)
- : mPort(port), mDevice(AUDIO_DEVICE_NONE),
- mClientInterface(clientInterface), mPatchHandle(AUDIO_PATCH_HANDLE_NONE), mId(0)
+ : mPort(port), mDevice(AUDIO_DEVICE_NONE), mClientInterface(clientInterface),
+ mPolicyMix(NULL), mGlobalActiveCount(0), mPatchHandle(AUDIO_PATCH_HANDLE_NONE), mId(0)
{
// clear usage count for all stream types
for (int i = 0; i < AUDIO_STREAM_CNT; i++) {
- mRefCount[i] = 0;
+ mActiveCount[i] = 0;
mCurVolume[i] = -1.0;
mMuteCount[i] = 0;
mStopTime[i] = 0;
@@ -103,17 +103,51 @@
}
}
-void AudioOutputDescriptor::changeRefCount(audio_stream_type_t stream,
+void AudioOutputDescriptor::changeStreamActiveCount(audio_stream_type_t stream,
int delta)
{
- if ((delta + (int)mRefCount[stream]) < 0) {
- ALOGW("changeRefCount() invalid delta %d for stream %d, refCount %d",
- delta, stream, mRefCount[stream]);
- mRefCount[stream] = 0;
+ if ((delta + (int)mActiveCount[stream]) < 0) {
+ ALOGW("%s invalid delta %d for stream %d, active count %d",
+ __FUNCTION__, delta, stream, mActiveCount[stream]);
+ mActiveCount[stream] = 0;
return;
}
- mRefCount[stream] += delta;
- ALOGV("changeRefCount() stream %d, count %d", stream, mRefCount[stream]);
+ mActiveCount[stream] += delta;
+ ALOGV("%s stream %d, count %d", __FUNCTION__, stream, mActiveCount[stream]);
+}
+
+void AudioOutputDescriptor::setClientActive(const sp<TrackClientDescriptor>& client, bool active)
+{
+ if (mClients.find(client->portId()) == mClients.end()
+ || active == client->active()) {
+ return;
+ }
+
+ changeStreamActiveCount(client->stream(), active ? 1 : -1);
+
+ // Handle non-client-specific activity ref count
+ int32_t oldGlobalActiveCount = mGlobalActiveCount;
+ if (!active && mGlobalActiveCount < 1) {
+ ALOGW("%s invalid deactivation with globalRefCount %d", __FUNCTION__, mGlobalActiveCount);
+ mGlobalActiveCount = 1;
+ }
+ mGlobalActiveCount += active ? 1 : -1;
+
+ if ((oldGlobalActiveCount == 0) && (mGlobalActiveCount > 0)) {
+ if ((mPolicyMix != NULL) && ((mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0))
+ {
+ mClientInterface->onDynamicPolicyMixStateUpdate(mPolicyMix->mDeviceAddress,
+ MIX_STATE_MIXING);
+ }
+ } else if ((oldGlobalActiveCount > 0) && (mGlobalActiveCount == 0)) {
+ if ((mPolicyMix != NULL) && ((mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0))
+ {
+ mClientInterface->onDynamicPolicyMixStateUpdate(mPolicyMix->mDeviceAddress,
+ MIX_STATE_IDLE);
+ }
+ }
+
+ client->setActive(active);
}
bool AudioOutputDescriptor::isActive(uint32_t inPastMs) const
@@ -137,7 +171,7 @@
uint32_t inPastMs,
nsecs_t sysTime) const
{
- if (mRefCount[stream] != 0) {
+ if (mActiveCount[stream] != 0) {
return true;
}
if (inPastMs == 0) {
@@ -231,11 +265,11 @@
result.append(buffer);
snprintf(buffer, SIZE, " Devices %08x\n", device());
result.append(buffer);
- snprintf(buffer, SIZE, " Stream volume refCount muteCount\n");
+ snprintf(buffer, SIZE, " Stream volume activeCount muteCount\n");
result.append(buffer);
for (int i = 0; i < (int)AUDIO_STREAM_CNT; i++) {
- snprintf(buffer, SIZE, " %02d %.03f %02d %02d\n",
- i, mCurVolume[i], mRefCount[i], mMuteCount[i]);
+ snprintf(buffer, SIZE, " %02d %.03f %02d %02d\n",
+ i, mCurVolume[i], streamActiveCount((audio_stream_type_t)i), mMuteCount[i]);
result.append(buffer);
}
@@ -261,9 +295,9 @@
AudioPolicyClientInterface *clientInterface)
: AudioOutputDescriptor(profile, clientInterface),
mProfile(profile), mIoHandle(AUDIO_IO_HANDLE_NONE), mLatency(0),
- mFlags((audio_output_flags_t)0), mPolicyMix(NULL),
+ mFlags((audio_output_flags_t)0),
mOutput1(0), mOutput2(0), mDirectOpenCount(0),
- mDirectClientSession(AUDIO_SESSION_NONE), mGlobalRefCount(0)
+ mDirectClientSession(AUDIO_SESSION_NONE)
{
if (profile != NULL) {
mFlags = (audio_output_flags_t)profile->getFlags();
@@ -327,41 +361,17 @@
}
}
-void SwAudioOutputDescriptor::changeRefCount(audio_stream_type_t stream,
+void SwAudioOutputDescriptor::changeStreamActiveCount(audio_stream_type_t stream,
int delta)
{
// forward usage count change to attached outputs
if (isDuplicated()) {
- mOutput1->changeRefCount(stream, delta);
- mOutput2->changeRefCount(stream, delta);
+ mOutput1->changeStreamActiveCount(stream, delta);
+ mOutput2->changeStreamActiveCount(stream, delta);
}
- AudioOutputDescriptor::changeRefCount(stream, delta);
-
- // handle stream-independent ref count
- uint32_t oldGlobalRefCount = mGlobalRefCount;
- if ((delta + (int)mGlobalRefCount) < 0) {
- ALOGW("changeRefCount() invalid delta %d globalRefCount %d", delta, mGlobalRefCount);
- mGlobalRefCount = 0;
- } else {
- mGlobalRefCount += delta;
- }
- if ((oldGlobalRefCount == 0) && (mGlobalRefCount > 0)) {
- if ((mPolicyMix != NULL) && ((mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0))
- {
- mClientInterface->onDynamicPolicyMixStateUpdate(mPolicyMix->mDeviceAddress,
- MIX_STATE_MIXING);
- }
-
- } else if ((oldGlobalRefCount > 0) && (mGlobalRefCount == 0)) {
- if ((mPolicyMix != NULL) && ((mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0))
- {
- mClientInterface->onDynamicPolicyMixStateUpdate(mPolicyMix->mDeviceAddress,
- MIX_STATE_IDLE);
- }
- }
+ AudioOutputDescriptor::changeStreamActiveCount(stream, delta);
}
-
bool SwAudioOutputDescriptor::isFixedVolume(audio_devices_t device)
{
// unit gain if rerouting to external policy
@@ -537,7 +547,7 @@
LOG_ALWAYS_FATAL_IF(mProfile->curOpenCount < 1, "%s profile open count %u",
__FUNCTION__, mProfile->curOpenCount);
- // do not call stop() here as stop() is supposed to be called after changeRefCount(-1)
+ // do not call stop() here as stop() is supposed to be called after setClientActive(false)
// and we don't know how many streams are still active at this time
if (isActive()) {
mProfile->curActiveCount--;
@@ -737,7 +747,7 @@
}
for (size_t i = 0; i < size(); i++) {
const sp<SwAudioOutputDescriptor> outputDesc = valueAt(i);
- if (outputDesc->mRefCount[s] != 0) {
+ if (outputDesc->streamActiveCount((audio_stream_type_t)s)!= 0) {
return true;
}
}
@@ -802,7 +812,7 @@
}
for (size_t i = 0; i < size(); i++) {
const sp<HwAudioOutputDescriptor> outputDesc = valueAt(i);
- if (outputDesc->mRefCount[s] != 0) {
+ if (outputDesc->streamActiveCount((audio_stream_type_t)s) != 0) {
return true;
}
}
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 2335135..5e98bee 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -1034,8 +1034,6 @@
}
return AUDIO_IO_HANDLE_NONE;
}
- outputDesc->mRefCount[stream] = 0;
- outputDesc->mStopTime[stream] = 0;
outputDesc->mDirectOpenCount = 1;
outputDesc->mDirectClientSession = session;
@@ -1394,8 +1392,7 @@
// increment usage count for this stream on the requested output:
// NOTE that the usage count is the same for duplicated output and hardware output which is
// necessary for a correct control of hardware output routing by startOutput() and stopOutput()
- outputDesc->changeRefCount(stream, 1);
- client->setActive(true);
+ outputDesc->setClientActive(client, true);
if (client->hasPreferredDevice(true)) {
device = getNewOutputDevice(outputDesc, false /*fromCache*/);
@@ -1408,7 +1405,7 @@
selectOutputForMusicEffects();
}
- if (outputDesc->mRefCount[stream] == 1 || device != AUDIO_DEVICE_NONE) {
+ if (outputDesc->streamActiveCount(stream) == 1 || device != AUDIO_DEVICE_NONE) {
// starting an output being rerouted?
if (device == AUDIO_DEVICE_NONE) {
device = getNewOutputDevice(outputDesc, false /*fromCache*/);
@@ -1537,8 +1534,8 @@
handleEventForBeacon(stream == AUDIO_STREAM_TTS ? STOPPING_BEACON : STOPPING_OUTPUT);
- if (outputDesc->mRefCount[stream] > 0) {
- if (outputDesc->mRefCount[stream] == 1) {
+ if (outputDesc->streamActiveCount(stream) > 0) {
+ if (outputDesc->streamActiveCount(stream) == 1) {
// Automatically disable the remote submix input when output is stopped on a
// re routing mix of type MIX_TYPE_RECORDERS
if (audio_is_remote_submix_device(outputDesc->mDevice) &&
@@ -1557,11 +1554,10 @@
}
// decrement usage count of this stream on the output
- outputDesc->changeRefCount(stream, -1);
- client->setActive(false);
+ outputDesc->setClientActive(client, false);
// store time at which the stream was stopped - see isStreamActive()
- if (outputDesc->mRefCount[stream] == 0 || forceDeviceUpdate) {
+ if (outputDesc->streamActiveCount(stream) == 0 || forceDeviceUpdate) {
outputDesc->mStopTime[stream] = systemTime();
audio_devices_t newDevice = getNewOutputDevice(outputDesc, false /*fromCache*/);
// delay the device switch by twice the latency because stopOutput() is executed when
@@ -4621,8 +4617,8 @@
// the other output.
bool wasActive = outputDesc2->isActive();
for (int j = 0; j < AUDIO_STREAM_CNT; j++) {
- int refCount = dupOutputDesc->mRefCount[j];
- outputDesc2->changeRefCount((audio_stream_type_t)j,-refCount);
+ int activeCount = dupOutputDesc->streamActiveCount((audio_stream_type_t)j);
+ outputDesc2->changeStreamActiveCount((audio_stream_type_t)j,-activeCount);
}
// stop() will be a no op if the output is still active but is needed in case all
// active streams refcounts where cleared above