Make max fast tracks configurable using a property
ro.audio.max_fast_tracks
Rename the currently configured maximum number of fast tracks
from FastMixerState::kMaxFastTracks to FastMixerState::sMaxFastTracks.
There is no guarantee that the CPU will be able to handle
the configured number of fast tracks.
Bug: 27564141
Change-Id: If9af226d839b226503488c3cb20a4bb8950b429d
diff --git a/services/audioflinger/FastMixer.cpp b/services/audioflinger/FastMixer.cpp
index 26cd1f9..546ef25 100644
--- a/services/audioflinger/FastMixer.cpp
+++ b/services/audioflinger/FastMixer.cpp
@@ -77,7 +77,7 @@
mSinkChannelMask = audio_channel_out_mask_from_count(mSinkChannelCount);
unsigned i;
- for (i = 0; i < FastMixerState::kMaxFastTracks; ++i) {
+ for (i = 0; i < FastMixerState::sMaxFastTracks; ++i) {
mFastTrackNames[i] = -1;
mGenerations[i] = 0;
}
@@ -187,7 +187,7 @@
// FIXME new may block for unbounded time at internal mutex of the heap
// implementation; it would be better to have normal mixer allocate for us
// to avoid blocking here and to prevent possible priority inversion
- mMixer = new AudioMixer(frameCount, mSampleRate, FastMixerState::kMaxFastTracks);
+ mMixer = new AudioMixer(frameCount, mSampleRate, FastMixerState::sMaxFastTracks);
const size_t mixerFrameSize = mSinkChannelCount
* audio_bytes_per_sample(mMixerBufferFormat);
mMixerBufferSize = mixerFrameSize * frameCount;
@@ -214,7 +214,7 @@
}
mMixerBufferState = UNDEFINED;
#if !LOG_NDEBUG
- for (unsigned i = 0; i < FastMixerState::kMaxFastTracks; ++i) {
+ for (unsigned i = 0; i < FastMixerState::sMaxFastTracks; ++i) {
mFastTrackNames[i] = -1;
}
#endif
diff --git a/services/audioflinger/FastMixerDumpState.cpp b/services/audioflinger/FastMixerDumpState.cpp
index b10942b..2326e2a 100644
--- a/services/audioflinger/FastMixerDumpState.cpp
+++ b/services/audioflinger/FastMixerDumpState.cpp
@@ -166,10 +166,10 @@
// Instead we always display all tracks, with an indication
// of whether we think the track is active.
uint32_t trackMask = mTrackMask;
- dprintf(fd, " Fast tracks: kMaxFastTracks=%u activeMask=%#x\n",
- FastMixerState::kMaxFastTracks, trackMask);
+ dprintf(fd, " Fast tracks: sMaxFastTracks=%u activeMask=%#x\n",
+ FastMixerState::sMaxFastTracks, trackMask);
dprintf(fd, " Index Active Full Partial Empty Recent Ready\n");
- for (uint32_t i = 0; i < FastMixerState::kMaxFastTracks; ++i, trackMask >>= 1) {
+ for (uint32_t i = 0; i < FastMixerState::sMaxFastTracks; ++i, trackMask >>= 1) {
bool isActive = trackMask & 1;
const FastTrackDump *ftDump = &mTracks[i];
const FastTrackUnderruns& underruns = ftDump->mUnderruns;
diff --git a/services/audioflinger/FastMixerState.cpp b/services/audioflinger/FastMixerState.cpp
index a8c2634..ad471fb 100644
--- a/services/audioflinger/FastMixerState.cpp
+++ b/services/audioflinger/FastMixerState.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include <cutils/properties.h>
#include "FastMixerState.h"
namespace android {
@@ -33,6 +34,10 @@
mFastTracksGen(0), mTrackMask(0), mOutputSink(NULL), mOutputSinkGen(0),
mFrameCount(0), mTeeSink(NULL)
{
+ int ok = pthread_once(&sMaxFastTracksOnce, sMaxFastTracksInit);
+ if (ok != 0) {
+ ALOGE("%s pthread_once failed: %d", __func__, ok);
+ }
}
FastMixerState::~FastMixerState()
@@ -40,6 +45,12 @@
}
// static
+unsigned FastMixerState::sMaxFastTracks = kDefaultFastTracks;
+
+// static
+pthread_once_t FastMixerState::sMaxFastTracksOnce = PTHREAD_ONCE_INIT;
+
+// static
const char *FastMixerState::commandToString(Command command)
{
const char *str = FastThreadState::commandToString(command);
@@ -54,4 +65,18 @@
LOG_ALWAYS_FATAL("%s", __func__);
}
+// static
+void FastMixerState::sMaxFastTracksInit()
+{
+ char value[PROPERTY_VALUE_MAX];
+ if (property_get("ro.audio.max_fast_tracks", value, NULL) > 0) {
+ char *endptr;
+ unsigned long ul = strtoul(value, &endptr, 0);
+ if (*endptr == '\0' && kMinFastTracks <= ul && ul <= kMaxFastTracks) {
+ sMaxFastTracks = (unsigned) ul;
+ }
+ }
+ ALOGI("sMaxFastTracks = %u", sMaxFastTracks);
+}
+
} // namespace android
diff --git a/services/audioflinger/FastMixerState.h b/services/audioflinger/FastMixerState.h
index 916514f..5a55c7a 100644
--- a/services/audioflinger/FastMixerState.h
+++ b/services/audioflinger/FastMixerState.h
@@ -54,7 +54,13 @@
FastMixerState();
/*virtual*/ ~FastMixerState();
- static const unsigned kMaxFastTracks = 8; // must be between 2 and 32 inclusive
+ // These are the minimum, maximum, and default values for maximum number of fast tracks
+ static const unsigned kMinFastTracks = 2;
+ static const unsigned kMaxFastTracks = 32;
+ static const unsigned kDefaultFastTracks = 8;
+
+ static unsigned sMaxFastTracks; // Configured maximum number of fast tracks
+ static pthread_once_t sMaxFastTracksOnce; // Protects initializer for sMaxFastTracks
// all pointer fields use raw pointers; objects are owned and ref-counted by the normal mixer
FastTrack mFastTracks[kMaxFastTracks];
@@ -76,6 +82,10 @@
// never returns NULL; asserts if command is invalid
static const char *commandToString(Command command);
+
+ // initialize sMaxFastTracks
+ static void sMaxFastTracksInit();
+
}; // struct FastMixerState
} // namespace android
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index ff67fb2..60aea87 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -1602,7 +1602,7 @@
mSignalPending(false),
mScreenState(AudioFlinger::mScreenState),
// index 0 is reserved for normal mixer's submix
- mFastTrackAvailMask(((1 << FastMixerState::kMaxFastTracks) - 1) & ~1),
+ mFastTrackAvailMask(((1 << FastMixerState::sMaxFastTracks) - 1) & ~1),
mHwSupportsPause(false), mHwPaused(false), mFlushPending(false)
{
snprintf(mThreadName, kThreadNameLength, "AudioOut_%X", id);
@@ -2103,7 +2103,7 @@
track->mName = -1;
if (track->isFastTrack()) {
int index = track->mFastIndex;
- ALOG_ASSERT(0 < index && index < (int)FastMixerState::kMaxFastTracks);
+ ALOG_ASSERT(0 < index && index < (int)FastMixerState::sMaxFastTracks);
ALOG_ASSERT(!(mFastTrackAvailMask & (1 << index)));
mFastTrackAvailMask |= 1 << index;
// redundant as track is about to be destroyed, for dumpsys only
@@ -3859,7 +3859,7 @@
// at the identical fast mixer slot within the same normal mix cycle,
// is impossible because the slot isn't marked available until the end of each cycle.
int j = track->mFastIndex;
- ALOG_ASSERT(0 < j && j < (int)FastMixerState::kMaxFastTracks);
+ ALOG_ASSERT(0 < j && j < (int)FastMixerState::sMaxFastTracks);
ALOG_ASSERT(!(mFastTrackAvailMask & (1 << j)));
FastTrack *fastTrack = &state->mFastTracks[j];
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index e71840d..16238f8 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -913,7 +913,7 @@
public:
virtual bool hasFastMixer() const { return mFastMixer != 0; }
virtual FastTrackUnderruns getFastTrackUnderruns(size_t fastIndex) const {
- ALOG_ASSERT(fastIndex < FastMixerState::kMaxFastTracks);
+ ALOG_ASSERT(fastIndex < FastMixerState::sMaxFastTracks);
return mFastMixerDumpState.mTracks[fastIndex].mUnderruns;
}
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 61b30c1..9d430aa 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -402,7 +402,7 @@
//mAudioTrackServerProxy->framesReadyIsCalledByMultipleThreads();
ALOG_ASSERT(thread->mFastTrackAvailMask != 0);
int i = __builtin_ctz(thread->mFastTrackAvailMask);
- ALOG_ASSERT(0 < i && i < (int)FastMixerState::kMaxFastTracks);
+ ALOG_ASSERT(0 < i && i < (int)FastMixerState::sMaxFastTracks);
// FIXME This is too eager. We allocate a fast track index before the
// fast track becomes active. Since fast tracks are a scarce resource,
// this means we are potentially denying other more important fast tracks from