Merge "Prevent onPrepared callback from being called twice" into klp-dev
diff --git a/media/libeffects/loudness/EffectLoudnessEnhancer.cpp b/media/libeffects/loudness/EffectLoudnessEnhancer.cpp
index dfc25db..91ed677 100644
--- a/media/libeffects/loudness/EffectLoudnessEnhancer.cpp
+++ b/media/libeffects/loudness/EffectLoudnessEnhancer.cpp
@@ -56,8 +56,7 @@
int32_t mTargetGainmB;// target gain in mB
// in this implementation, there is no coupling between the compression on the left and right
// channels
- le_fx::AdaptiveDynamicRangeCompression* mCompressorL;
- le_fx::AdaptiveDynamicRangeCompression* mCompressorR;
+ le_fx::AdaptiveDynamicRangeCompression* mCompressor;
};
//
@@ -68,11 +67,10 @@
{
ALOGV(" > LE_reset(%p)", pContext);
- if ((pContext->mCompressorL != NULL) && (pContext->mCompressorR != NULL)) {
+ if (pContext->mCompressor != NULL) {
float targetAmp = pow(10, pContext->mTargetGainmB/2000.0f); // mB to linear amplification
ALOGV("LE_reset(): Target gain=%dmB <=> factor=%.2fX", pContext->mTargetGainmB, targetAmp);
- pContext->mCompressorL->Initialize(targetAmp, pContext->mConfig.inputCfg.samplingRate);
- pContext->mCompressorR->Initialize(targetAmp, pContext->mConfig.inputCfg.samplingRate);
+ pContext->mCompressor->Initialize(targetAmp, pContext->mConfig.inputCfg.samplingRate);
} else {
ALOGE("LE_reset(%p): null compressors, can't apply target gain", pContext);
}
@@ -176,13 +174,9 @@
float targetAmp = pow(10, pContext->mTargetGainmB/2000.0f); // mB to linear amplification
ALOGV("LE_init(): Target gain=%dmB <=> factor=%.2fX", pContext->mTargetGainmB, targetAmp);
- if (pContext->mCompressorL == NULL) {
- pContext->mCompressorL = new le_fx::AdaptiveDynamicRangeCompression();
- pContext->mCompressorL->Initialize(targetAmp, pContext->mConfig.inputCfg.samplingRate);
- }
- if (pContext->mCompressorR == NULL) {
- pContext->mCompressorR = new le_fx::AdaptiveDynamicRangeCompression();
- pContext->mCompressorR->Initialize(targetAmp, pContext->mConfig.inputCfg.samplingRate);
+ if (pContext->mCompressor == NULL) {
+ pContext->mCompressor = new le_fx::AdaptiveDynamicRangeCompression();
+ pContext->mCompressor->Initialize(targetAmp, pContext->mConfig.inputCfg.samplingRate);
}
LE_setConfig(pContext, &pContext->mConfig);
@@ -215,8 +209,7 @@
pContext->mItfe = &gLEInterface;
pContext->mState = LOUDNESS_ENHANCER_STATE_UNINITIALIZED;
- pContext->mCompressorL = NULL;
- pContext->mCompressorR = NULL;
+ pContext->mCompressor = NULL;
ret = LE_init(pContext);
if (ret < 0) {
ALOGW("LELib_Create() init failed");
@@ -242,13 +235,9 @@
return -EINVAL;
}
pContext->mState = LOUDNESS_ENHANCER_STATE_UNINITIALIZED;
- if (pContext->mCompressorL != NULL) {
- delete pContext->mCompressorL;
- pContext->mCompressorL = NULL;
- }
- if (pContext->mCompressorR != NULL) {
- delete pContext->mCompressorR;
- pContext->mCompressorR = NULL;
+ if (pContext->mCompressor != NULL) {
+ delete pContext->mCompressor;
+ pContext->mCompressor = NULL;
}
delete pContext;
@@ -293,11 +282,14 @@
//ALOGV("LE about to process %d samples", inBuffer->frameCount);
uint16_t inIdx;
float inputAmp = pow(10, pContext->mTargetGainmB/2000.0f);
+ float leftSample, rightSample;
for (inIdx = 0 ; inIdx < inBuffer->frameCount ; inIdx++) {
- inBuffer->s16[2*inIdx] = pContext->mCompressorL->Compress(
- inputAmp * (float)inBuffer->s16[2*inIdx]);
- inBuffer->s16[2*inIdx +1] = pContext->mCompressorR->Compress(
- inputAmp * (float)inBuffer->s16[2*inIdx +1]);
+ // makeup gain is applied on the input of the compressor
+ leftSample = inputAmp * (float)inBuffer->s16[2*inIdx];
+ rightSample = inputAmp * (float)inBuffer->s16[2*inIdx +1];
+ pContext->mCompressor->Compress(&leftSample, &rightSample);
+ inBuffer->s16[2*inIdx] = (int16_t) leftSample;
+ inBuffer->s16[2*inIdx +1] = (int16_t) rightSample;
}
if (inBuffer->raw != outBuffer->raw) {
diff --git a/media/libeffects/loudness/dsp/core/dynamic_range_compression-inl.h b/media/libeffects/loudness/dsp/core/dynamic_range_compression-inl.h
index fed8c2a..da75ceb 100644
--- a/media/libeffects/loudness/dsp/core/dynamic_range_compression-inl.h
+++ b/media/libeffects/loudness/dsp/core/dynamic_range_compression-inl.h
@@ -35,7 +35,7 @@
float target_gain) {
const float decibel = target_gain_to_knee_threshold_.Interpolate(
target_gain);
- ALOGE("set_knee_threshold_via_target_gain: decibel =%.3f", decibel);
+ ALOGV("set_knee_threshold_via_target_gain: decibel =%.3fdB", decibel);
set_knee_threshold(decibel);
}
diff --git a/media/libeffects/loudness/dsp/core/dynamic_range_compression.cpp b/media/libeffects/loudness/dsp/core/dynamic_range_compression.cpp
index 2bbd043..7bd068e 100644
--- a/media/libeffects/loudness/dsp/core/dynamic_range_compression.cpp
+++ b/media/libeffects/loudness/dsp/core/dynamic_range_compression.cpp
@@ -102,5 +102,40 @@
return x;
}
+void AdaptiveDynamicRangeCompression::Compress(float *x1, float *x2) {
+ // Taking the maximum amplitude of both channels
+ const float max_abs_x = std::max(std::fabs(*x1),
+ std::max(std::fabs(*x2), kMinLogAbsValue));
+ const float max_abs_x_dB = math::fast_log(max_abs_x);
+ // Subtract Threshold from log-encoded input to get the amount of overshoot
+ const float overshoot = max_abs_x_dB - knee_threshold_;
+ // Hard half-wave rectifier
+ const float rect = std::max(overshoot, 0.0f);
+ // Multiply rectified overshoot with slope
+ const float cv = rect * slope_;
+ const float prev_state = state_;
+ if (cv <= state_) {
+ state_ = alpha_attack_ * state_ + (1.0f - alpha_attack_) * cv;
+ } else {
+ state_ = alpha_release_ * state_ + (1.0f - alpha_release_) * cv;
+ }
+ compressor_gain_ *=
+ math::ExpApproximationViaTaylorExpansionOrder5(state_ - prev_state);
+ *x1 *= compressor_gain_;
+ if (*x1 > kFixedPointLimit) {
+ *x1 = kFixedPointLimit;
+ }
+ if (*x1 < -kFixedPointLimit) {
+ *x1 = -kFixedPointLimit;
+ }
+ *x2 *= compressor_gain_;
+ if (*x2 > kFixedPointLimit) {
+ *x2 = kFixedPointLimit;
+ }
+ if (*x2 < -kFixedPointLimit) {
+ *x2 = -kFixedPointLimit;
+ }
+}
+
} // namespace le_fx
diff --git a/media/libeffects/loudness/dsp/core/dynamic_range_compression.h b/media/libeffects/loudness/dsp/core/dynamic_range_compression.h
index 4c015df..2821a78 100644
--- a/media/libeffects/loudness/dsp/core/dynamic_range_compression.h
+++ b/media/libeffects/loudness/dsp/core/dynamic_range_compression.h
@@ -55,6 +55,9 @@
// log(.) and exp(.).
float Compress(float x);
+ // Stereo channel version of the compressor
+ void Compress(float *x1, float *x2);
+
// This version is slower than Compress(.) but faster than CompressSlow(.)
float CompressNormalSpeed(float x);
diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp
index e38e261..a8a8786 100644
--- a/media/libstagefright/AudioPlayer.cpp
+++ b/media/libstagefright/AudioPlayer.cpp
@@ -363,6 +363,7 @@
mPositionTimeMediaUs = -1;
mPositionTimeRealUs = -1;
mSeeking = false;
+ mSeekTimeUs = 0;
mReachedEOS = false;
mFinalStatus = OK;
mStarted = false;
@@ -602,15 +603,24 @@
// need to adjust the mStartPosUs for offload decoding since parser
// might not be able to get the exact seek time requested.
- if (refreshSeekTime && useOffload()) {
- if (postSeekComplete) {
- ALOGV("fillBuffer is going to post SEEK_COMPLETE");
- mObserver->postAudioSeekComplete();
- postSeekComplete = false;
- }
+ if (refreshSeekTime) {
+ if (useOffload()) {
+ if (postSeekComplete) {
+ ALOGV("fillBuffer is going to post SEEK_COMPLETE");
+ mObserver->postAudioSeekComplete();
+ postSeekComplete = false;
+ }
- mStartPosUs = mPositionTimeMediaUs;
- ALOGV("adjust seek time to: %.2f", mStartPosUs/ 1E6);
+ mStartPosUs = mPositionTimeMediaUs;
+ ALOGV("adjust seek time to: %.2f", mStartPosUs/ 1E6);
+ }
+ // clear seek time with mLock locked and once we have valid mPositionTimeMediaUs
+ // and mPositionTimeRealUs
+ // before clearing mSeekTimeUs check if a new seek request has been received while
+ // we were reading from the source with mLock released.
+ if (!mSeeking) {
+ mSeekTimeUs = 0;
+ }
}
if (!useOffload()) {
@@ -741,12 +751,10 @@
return mPositionTimeRealUs;
}
- if (mPositionTimeMediaUs < 0 || mPositionTimeRealUs < 0) {
- if (mSeeking) {
- return mSeekTimeUs;
- }
- return 0;
+ if (mPositionTimeMediaUs < 0 || mPositionTimeRealUs < 0) {
+ // mSeekTimeUs is either seek time while seeking or 0 if playback did not start.
+ return mSeekTimeUs;
}
int64_t realTimeOffset = getRealTimeUsLocked() - mPositionTimeRealUs;
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index bcf9cd3..3b516af 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -928,6 +928,9 @@
if ((err != OK) && mOffloadAudio) {
ALOGI("play_l() cannot create offload output, fallback to sw decode");
+ int64_t curTimeUs;
+ getPosition(&curTimeUs);
+
delete mAudioPlayer;
mAudioPlayer = NULL;
// if the player was started it will take care of stopping the source when destroyed
@@ -943,6 +946,10 @@
if (err != OK) {
mAudioSource.clear();
} else {
+ mSeekNotificationSent = true;
+ if (mExtractorFlags & MediaExtractor::CAN_SEEK) {
+ seekTo_l(curTimeUs);
+ }
createAudioPlayer_l();
err = startAudioPlayer_l(false);
}
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index 0ca2107..6e0354d 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -1279,9 +1279,10 @@
}
bool isGlobalSession = (mSessionId == AUDIO_SESSION_OUTPUT_MIX) ||
(mSessionId == AUDIO_SESSION_OUTPUT_STAGE);
- // always process effects unless no more tracks are on the session and the effect tail
- // has been rendered
- bool doProcess = true;
+ // never process effects when:
+ // - on an OFFLOAD thread
+ // - no more tracks are on the session and the effect tail has been rendered
+ bool doProcess = (thread->type() != ThreadBase::OFFLOAD);
if (!isGlobalSession) {
bool tracksOnSession = (trackCnt() != 0);
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index b771e3b..2d9d485 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -1594,6 +1594,7 @@
if (mOutput->stream->set_callback(mOutput->stream,
AudioFlinger::PlaybackThread::asyncCallback, this) == 0) {
mUseAsyncWrite = true;
+ mCallbackThread = new AudioFlinger::AsyncCallbackThread(this);
}
}
@@ -3746,9 +3747,9 @@
// ----------------------------------------------------------------------------
AudioFlinger::AsyncCallbackThread::AsyncCallbackThread(
- const sp<AudioFlinger::OffloadThread>& offloadThread)
+ const wp<AudioFlinger::PlaybackThread>& playbackThread)
: Thread(false /*canCallJava*/),
- mOffloadThread(offloadThread),
+ mPlaybackThread(playbackThread),
mWriteAckSequence(0),
mDrainSequence(0)
{
@@ -3783,13 +3784,13 @@
mDrainSequence &= ~1;
}
{
- sp<AudioFlinger::OffloadThread> offloadThread = mOffloadThread.promote();
- if (offloadThread != 0) {
+ sp<AudioFlinger::PlaybackThread> playbackThread = mPlaybackThread.promote();
+ if (playbackThread != 0) {
if (writeAckSequence & 1) {
- offloadThread->resetWriteBlocked(writeAckSequence >> 1);
+ playbackThread->resetWriteBlocked(writeAckSequence >> 1);
}
if (drainSequence & 1) {
- offloadThread->resetDraining(drainSequence >> 1);
+ playbackThread->resetDraining(drainSequence >> 1);
}
}
}
@@ -3847,7 +3848,6 @@
mHwPaused(false),
mPausedBytesRemaining(0)
{
- mCallbackThread = new AudioFlinger::AsyncCallbackThread(this);
}
AudioFlinger::OffloadThread::~OffloadThread()
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 443b8d7..241424f 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -759,7 +759,7 @@
class AsyncCallbackThread : public Thread {
public:
- AsyncCallbackThread(const sp<OffloadThread>& offloadThread);
+ AsyncCallbackThread(const wp<PlaybackThread>& playbackThread);
virtual ~AsyncCallbackThread();
@@ -776,17 +776,17 @@
void resetDraining();
private:
- wp<OffloadThread> mOffloadThread;
+ const wp<PlaybackThread> mPlaybackThread;
// mWriteAckSequence corresponds to the last write sequence passed by the offload thread via
// setWriteBlocked(). The sequence is shifted one bit to the left and the lsb is used
// to indicate that the callback has been received via resetWriteBlocked()
- uint32_t mWriteAckSequence;
+ uint32_t mWriteAckSequence;
// mDrainSequence corresponds to the last drain sequence passed by the offload thread via
// setDraining(). The sequence is shifted one bit to the left and the lsb is used
// to indicate that the callback has been received via resetDraining()
- uint32_t mDrainSequence;
- Condition mWaitWorkCV;
- Mutex mLock;
+ uint32_t mDrainSequence;
+ Condition mWaitWorkCV;
+ Mutex mLock;
};
class DuplicatingThread : public MixerThread {
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index 83466cb..76d44bf 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -298,11 +298,28 @@
}
}
+ // HACK b/10949105
+ // Query consumer usage bits to set async operation mode for
+ // GLConsumer using controlledByApp parameter.
+ bool useAsync = false;
+ int32_t consumerUsage;
+ if ((res = bufferProducer->query(NATIVE_WINDOW_CONSUMER_USAGE_BITS,
+ &consumerUsage)) != OK) {
+ ALOGE("%s: Camera %d: Failed to query consumer usage", __FUNCTION__,
+ mCameraId);
+ return res;
+ }
+ if (consumerUsage & GraphicBuffer::USAGE_HW_TEXTURE) {
+ ALOGW("%s: Camera %d: Forcing asynchronous mode for stream",
+ __FUNCTION__, mCameraId);
+ useAsync = true;
+ }
+
sp<IBinder> binder;
sp<ANativeWindow> anw;
if (bufferProducer != 0) {
binder = bufferProducer->asBinder();
- anw = new Surface(bufferProducer);
+ anw = new Surface(bufferProducer, useAsync);
}
// TODO: remove w,h,f since we are ignoring them