merge in jb-release history after reset to jb-dev
diff --git a/include/private/media/AudioTrackShared.h b/include/private/media/AudioTrackShared.h
index 469f5ff..5b133f3 100644
--- a/include/private/media/AudioTrackShared.h
+++ b/include/private/media/AudioTrackShared.h
@@ -97,9 +97,7 @@
// read-only for client, server writes once at initialization and is then read-only
uint8_t frameSize; // would normally be size_t, but 8 bits is plenty
-
- // never used
- uint8_t pad1;
+ uint8_t mName; // normal tracks: track name, fast tracks: track index
// used by client only
uint16_t bufferTimeoutMs; // Maximum cumulated timeout before restarting audioflinger
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index e234532..e5a60f5 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -491,6 +491,7 @@
AutoMutex lock(mLock);
if (mActive) {
mActive = false;
+ mCblk->cv.signal();
mAudioTrack->pause();
}
}
@@ -987,8 +988,8 @@
// timing out when a loop has been set and we have already written upto loop end
// is a normal condition: no need to wake AudioFlinger up.
if (cblk->user < cblk->loopEnd) {
- ALOGW( "obtainBuffer timed out (is the CPU pegged?) %p "
- "user=%08x, server=%08x", this, cblk->user, cblk->server);
+ ALOGW( "obtainBuffer timed out (is the CPU pegged?) %p name=%#x"
+ "user=%08x, server=%08x", this, cblk->mName, cblk->user, cblk->server);
//unlock cblk mutex before calling mAudioTrack->start() (see issue #1617140)
cblk->lock.unlock();
result = mAudioTrack->start();
@@ -1054,7 +1055,7 @@
// restart track if it was disabled by audioflinger due to previous underrun
if (mActive && (mCblk->flags & CBLK_DISABLED_MSK)) {
android_atomic_and(~CBLK_DISABLED_ON, &mCblk->flags);
- ALOGW("releaseBuffer() track %p disabled, restarting", this);
+ ALOGW("releaseBuffer() track %p name=%#x disabled, restarting", this, mCblk->mName);
mAudioTrack->start();
}
}
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index d7f721f..0f346d8 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -2440,7 +2440,7 @@
CHECK(meta->findCString(kKeyMIMEType, &mime));
isAudioTrack = !strncasecmp(mime, "audio/", 6);
- if (!isAudioTrack && !strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) {
+ if (!isAudioTrack && strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP) != 0) {
ALOGE("Track %d is not either audio or timed text", trackIndex);
return ERROR_UNSUPPORTED;
}
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 7fb395e..fde7ebf 100755
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -1921,6 +1921,14 @@
goto error;
}
+ err = native_window_set_scaling_mode(mNativeWindow.get(),
+ NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
+ if (err != OK) {
+ ALOGE("error pushing blank frames: set_scaling_mode failed: %s (%d)",
+ strerror(-err), -err);
+ goto error;
+ }
+
err = mNativeWindow->query(mNativeWindow.get(),
NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &minUndequeuedBufs);
if (err != NO_ERROR) {
diff --git a/media/libstagefright/VBRISeeker.cpp b/media/libstagefright/VBRISeeker.cpp
index bcba874..a245f2c 100644
--- a/media/libstagefright/VBRISeeker.cpp
+++ b/media/libstagefright/VBRISeeker.cpp
@@ -93,7 +93,13 @@
sp<VBRISeeker> seeker = new VBRISeeker;
seeker->mBasePos = post_id3_pos + frameSize;
- seeker->mDurationUs = durationUs;
+ // only update mDurationUs if the calculated duration is valid (non zero)
+ // otherwise, leave duration at -1 so that getDuration() and getOffsetForTime()
+ // return false when called, to indicate that this vbri tag does not have the
+ // requested information
+ if (durationUs) {
+ seeker->mDurationUs = durationUs;
+ }
off64_t offset = post_id3_pos;
for (size_t i = 0; i < numEntries; ++i) {
diff --git a/media/libstagefright/XINGSeeker.cpp b/media/libstagefright/XINGSeeker.cpp
index 9c91134..81ed9c6 100644
--- a/media/libstagefright/XINGSeeker.cpp
+++ b/media/libstagefright/XINGSeeker.cpp
@@ -29,7 +29,8 @@
: mDurationUs(-1),
mSizeBytes(0),
mEncoderDelay(0),
- mEncoderPadding(0) {
+ mEncoderPadding(0),
+ mTOCValid(false) {
}
bool XINGSeeker::getDuration(int64_t *durationUs) {
@@ -81,10 +82,6 @@
seeker->mFirstFramePos = first_frame_pos;
- seeker->mSizeBytes = 0;
- seeker->mTOCValid = false;
- seeker->mDurationUs = 0;
-
uint8_t buffer[4];
int offset = first_frame_pos;
if (source->readAt(offset, &buffer, 4) < 4) { // get header
@@ -140,7 +137,13 @@
return NULL;
}
int32_t frames = U32_AT(buffer);
- seeker->mDurationUs = (int64_t)frames * samples_per_frame * 1000000LL / sampling_rate;
+ // only update mDurationUs if the calculated duration is valid (non zero)
+ // otherwise, leave duration at -1 so that getDuration() and getOffsetForTime()
+ // return false when called, to indicate that this xing tag does not have the
+ // requested information
+ if (frames) {
+ seeker->mDurationUs = (int64_t)frames * samples_per_frame * 1000000LL / sampling_rate;
+ }
offset += 4;
}
if (flags & 0x0002) { // Bytes field is present
diff --git a/services/audioflinger/Android.mk b/services/audioflinger/Android.mk
index f32d90f..8473fab 100644
--- a/services/audioflinger/Android.mk
+++ b/services/audioflinger/Android.mk
@@ -84,6 +84,9 @@
LOCAL_CFLAGS += -DFAST_MIXER_STATISTICS
+# uncomment to display CPU load adjusted for CPU frequency
+# LOCAL_CFLAGS += -DCPU_FREQUENCY_STATISTICS
+
LOCAL_CFLAGS += -DSTATE_QUEUE_INSTANTIATIONS='"StateQueueInstantiations.cpp"'
LOCAL_CFLAGS += -DHAVE_REQUEST_PRIORITY -UFAST_TRACKS_AT_NON_NATIVE_SAMPLE_RATE -USOAKER
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 586a916..b78c6d1 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -1700,7 +1700,7 @@
ALOGV("AUDIO_OUTPUT_FLAG_FAST accepted: frameCount=%d mFrameCount=%d",
frameCount, mFrameCount);
} else {
- ALOGW("AUDIO_OUTPUT_FLAG_FAST denied: isTimed=%d sharedBuffer=%p frameCount=%d "
+ ALOGV("AUDIO_OUTPUT_FLAG_FAST denied: isTimed=%d sharedBuffer=%p frameCount=%d "
"mFrameCount=%d format=%d isLinear=%d channelMask=%d sampleRate=%d mSampleRate=%d "
"hasFastMixer=%d tid=%d fastTrackAvailMask=%#x",
isTimed, sharedBuffer.get(), frameCount, mFrameCount, format,
@@ -4287,6 +4287,7 @@
mCblk->frameSize = audio_is_linear_pcm(format) ? mChannelCount * sizeof(int16_t) : sizeof(uint8_t);
// to avoid leaking a track name, do not allocate one unless there is an mCblk
mName = thread->getTrackName_l((audio_channel_mask_t)channelMask);
+ mCblk->mName = mName;
if (mName < 0) {
ALOGE("no more track names available");
return;
@@ -4302,6 +4303,7 @@
// this means we are potentially denying other more important fast tracks from
// being created. It would be better to allocate the index dynamically.
mFastIndex = i;
+ mCblk->mName = i;
// Read the initial underruns because this field is never cleared by the fast mixer
mObservedUnderruns = thread->getFastTrackUnderruns(i);
thread->mFastTrackAvailMask &= ~(1 << i);
diff --git a/services/audioflinger/FastMixer.cpp b/services/audioflinger/FastMixer.cpp
index 3bb7b44..7652132 100644
--- a/services/audioflinger/FastMixer.cpp
+++ b/services/audioflinger/FastMixer.cpp
@@ -24,13 +24,16 @@
#include <system/audio.h>
#ifdef FAST_MIXER_STATISTICS
#include <cpustats/CentralTendencyStatistics.h>
+#ifdef CPU_FREQUENCY_STATISTICS
#include <cpustats/ThreadCpuUsage.h>
#endif
+#endif
#include "AudioMixer.h"
#include "FastMixer.h"
#define FAST_HOT_IDLE_NS 1000000L // 1 ms: time to sleep while hot idling
#define FAST_DEFAULT_NS 999999999L // ~1 sec: default time to sleep
+#define MIN_WARMUP_CYCLES 2 // minimum number of loop cycles to wait for warmup
#define MAX_WARMUP_CYCLES 10 // maximum number of loop cycles to wait for warmup
namespace android {
@@ -63,6 +66,7 @@
long periodNs = 0; // expected period; the time required to render one mix buffer
long underrunNs = 0; // underrun likely when write cycle is greater than this value
long overrunNs = 0; // overrun likely when write cycle is less than this value
+ long forceNs = 0; // if overrun detected, force the write cycle to take this much time
long warmupNs = 0; // warmup complete when write cycle is greater than to this value
FastMixerDumpState dummyDumpState, *dumpState = &dummyDumpState;
bool ignoreNextOverrun = true; // used to ignore initial overrun and first after an underrun
@@ -71,8 +75,10 @@
bool oldLoadValid = false; // whether oldLoad is valid
uint32_t bounds = 0;
bool full = false; // whether we have collected at least kSamplingN samples
+#ifdef CPU_FREQUENCY_STATISTICS
ThreadCpuUsage tcu; // for reading the current CPU clock frequency in kHz
#endif
+#endif
unsigned coldGen = 0; // last observed mColdGen
bool isWarm = false; // true means ready to mix, false means wait for warmup before mixing
struct timespec measuredWarmupTs = {0, 0}; // how long did it take for warmup to complete
@@ -217,11 +223,14 @@
periodNs = (frameCount * 1000000000LL) / sampleRate; // 1.00
underrunNs = (frameCount * 1750000000LL) / sampleRate; // 1.75
overrunNs = (frameCount * 250000000LL) / sampleRate; // 0.25
+ forceNs = (frameCount * 750000000LL) / sampleRate; // 0.75
warmupNs = (frameCount * 500000000LL) / sampleRate; // 0.50
} else {
periodNs = 0;
underrunNs = 0;
overrunNs = 0;
+ forceNs = 0;
+ warmupNs = 0;
}
mixBufferState = UNDEFINED;
#if !LOG_NDEBUG
@@ -446,7 +455,7 @@
// To avoid an initial underrun on fast tracks after exiting standby,
// do not start pulling data from tracks and mixing until warmup is complete.
// Warmup is considered complete after the earlier of:
- // first successful single write() that blocks for more than warmupNs
+ // MIN_WARMUP_CYCLES write() attempts and last one blocks for at least warmupNs
// MAX_WARMUP_CYCLES write() attempts.
// This is overly conservative, but to get better accuracy requires a new HAL API.
if (!isWarm && attemptedWrite) {
@@ -457,13 +466,15 @@
measuredWarmupTs.tv_nsec -= 1000000000;
}
++warmupCycles;
- if ((attemptedWrite && nsec > warmupNs) ||
+ if ((nsec > warmupNs && warmupCycles >= MIN_WARMUP_CYCLES) ||
(warmupCycles >= MAX_WARMUP_CYCLES)) {
isWarm = true;
dumpState->mMeasuredWarmupTs = measuredWarmupTs;
dumpState->mWarmupCycles = warmupCycles;
}
}
+ sleepNs = -1;
+ if (isWarm) {
if (sec > 0 || nsec > underrunNs) {
#if defined(ATRACE_TAG) && (ATRACE_TAG != ATRACE_TAG_NEVER)
ScopedTrace st(ATRACE_TAG, "underrun");
@@ -472,7 +483,6 @@
ALOGV("underrun: time since last cycle %d.%03ld sec",
(int) sec, nsec / 1000000L);
dumpState->mUnderruns++;
- sleepNs = -1;
ignoreNextOverrun = true;
} else if (nsec < overrunNs) {
if (ignoreNextOverrun) {
@@ -483,15 +493,19 @@
(int) sec, nsec / 1000000L);
dumpState->mOverruns++;
}
- // Code for non blocking audio HAL. Sleep time must be tuned to allow
- // catching up after an underrun
- // sleepNs = periodNs - overrunNs;
- sleepNs = -1;
+ // This forces a minimum cycle time. It:
+ // - compensates for an audio HAL with jitter due to sample rate conversion
+ // - works with a variable buffer depth audio HAL that never pulls at a rate
+ // < than overrunNs per buffer.
+ // - recovers from overrun immediately after underrun
+ // It doesn't work with a non-blocking audio HAL.
+ sleepNs = forceNs - nsec;
} else {
- sleepNs = -1;
ignoreNextOverrun = false;
}
+ }
#ifdef FAST_MIXER_STATISTICS
+ if (isWarm) {
// advance the FIFO queue bounds
size_t i = bounds & (FastMixerDumpState::kSamplingN - 1);
bounds = (bounds & 0xFFFF0000) | ((bounds + 1) & 0xFFFF);
@@ -527,16 +541,20 @@
}
oldLoad = newLoad;
}
+#ifdef CPU_FREQUENCY_STATISTICS
// get the absolute value of CPU clock frequency in kHz
int cpuNum = sched_getcpu();
uint32_t kHz = tcu.getCpukHz(cpuNum);
kHz = (kHz << 4) | (cpuNum & 0xF);
+#endif
// save values in FIFO queues for dumpsys
// these stores #1, #2, #3 are not atomic with respect to each other,
// or with respect to store #4 below
dumpState->mMonotonicNs[i] = monotonicNs;
dumpState->mLoadNs[i] = loadNs;
+#ifdef CPU_FREQUENCY_STATISTICS
dumpState->mCpukHz[i] = kHz;
+#endif
// this store #4 is not atomic with respect to stores #1, #2, #3 above, but
// the newest open and oldest closed halves are atomic with respect to each other
dumpState->mBounds = bounds;
@@ -544,6 +562,7 @@
ATRACE_INT("cycle_ms", monotonicNs / 1000000);
ATRACE_INT("load_us", loadNs / 1000);
#endif
+ }
#endif
} else {
// first time through the loop
@@ -579,7 +598,9 @@
// so clearing reduces chance for dumpsys to read random uninitialized samples
memset(&mMonotonicNs, 0, sizeof(mMonotonicNs));
memset(&mLoadNs, 0, sizeof(mLoadNs));
+#ifdef CPU_FREQUENCY_STATISTICS
memset(&mCpukHz, 0, sizeof(mCpukHz));
+#endif
}
FastMixerDumpState::~FastMixerDumpState()
@@ -588,6 +609,10 @@
void FastMixerDumpState::dump(int fd)
{
+ if (mCommand == FastMixerState::INITIAL) {
+ fdprintf(fd, "FastMixer not initialized\n");
+ return;
+ }
#define COMMAND_MAX 32
char string[COMMAND_MAX];
switch (mCommand) {
@@ -639,18 +664,20 @@
}
// statistics for monotonic (wall clock) time, thread raw CPU load in time, CPU clock frequency,
// and adjusted CPU load in MHz normalized for CPU clock frequency
- CentralTendencyStatistics wall, loadNs, kHz, loadMHz;
- // only compute adjusted CPU load in Hz if current CPU number and CPU clock frequency are stable
- bool valid = false;
+ CentralTendencyStatistics wall, loadNs;
+#ifdef CPU_FREQUENCY_STATISTICS
+ CentralTendencyStatistics kHz, loadMHz;
uint32_t previousCpukHz = 0;
+#endif
// loop over all the samples
for (; n > 0; --n) {
size_t i = oldestClosed++ & (kSamplingN - 1);
uint32_t wallNs = mMonotonicNs[i];
wall.sample(wallNs);
uint32_t sampleLoadNs = mLoadNs[i];
- uint32_t sampleCpukHz = mCpukHz[i];
loadNs.sample(sampleLoadNs);
+#ifdef CPU_FREQUENCY_STATISTICS
+ uint32_t sampleCpukHz = mCpukHz[i];
// skip bad kHz samples
if ((sampleCpukHz & ~0xF) != 0) {
kHz.sample(sampleCpukHz >> 4);
@@ -661,6 +688,7 @@
}
}
previousCpukHz = sampleCpukHz;
+#endif
}
fdprintf(fd, "Simple moving statistics over last %.1f seconds:\n", wall.n() * mixPeriodSec);
fdprintf(fd, " wall clock time in ms per mix cycle:\n"
@@ -670,6 +698,7 @@
" mean=%.0f min=%.0f max=%.0f stddev=%.0f\n",
loadNs.mean()*1e-3, loadNs.minimum()*1e-3, loadNs.maximum()*1e-3,
loadNs.stddev()*1e-3);
+#ifdef CPU_FREQUENCY_STATISTICS
fdprintf(fd, " CPU clock frequency in MHz:\n"
" mean=%.0f min=%.0f max=%.0f stddev=%.0f\n",
kHz.mean()*1e-3, kHz.minimum()*1e-3, kHz.maximum()*1e-3, kHz.stddev()*1e-3);
@@ -677,6 +706,7 @@
" mean=%.1f min=%.1f max=%.1f stddev=%.1f\n",
loadMHz.mean(), loadMHz.minimum(), loadMHz.maximum(), loadMHz.stddev());
#endif
+#endif
// The active track mask and track states are updated non-atomically.
// So if we relied on isActive to decide whether to display,
// then we might display an obsolete track or omit an active track.
diff --git a/services/audioflinger/FastMixer.h b/services/audioflinger/FastMixer.h
index 06e76d5..462739b 100644
--- a/services/audioflinger/FastMixer.h
+++ b/services/audioflinger/FastMixer.h
@@ -116,8 +116,10 @@
// The elements in the *Ns arrays are in units of nanoseconds <= 3999999999.
uint32_t mMonotonicNs[kSamplingN]; // delta monotonic (wall clock) time
uint32_t mLoadNs[kSamplingN]; // delta CPU load in time
+#ifdef CPU_FREQUENCY_STATISTICS
uint32_t mCpukHz[kSamplingN]; // absolute CPU clock frequency in kHz, bits 0-3 are CPU#
#endif
+#endif
};
} // namespace android