Merge "audio policy: support platforms with no audio devices" into nyc-dev
diff --git a/camera/aidl/android/hardware/camera2/ICameraDeviceCallbacks.aidl b/camera/aidl/android/hardware/camera2/ICameraDeviceCallbacks.aidl
index ab57db5..755ec8e 100644
--- a/camera/aidl/android/hardware/camera2/ICameraDeviceCallbacks.aidl
+++ b/camera/aidl/android/hardware/camera2/ICameraDeviceCallbacks.aidl
@@ -37,4 +37,11 @@
oneway void onResultReceived(in CameraMetadataNative result,
in CaptureResultExtras resultExtras);
oneway void onPrepared(int streamId);
+
+ /**
+ * Repeating request encountered an error and was stopped.
+ *
+ * @param lastFrameNumber Frame number of the last frame of the streaming request.
+ */
+ oneway void onRepeatingRequestError(in long lastFrameNumber);
}
diff --git a/camera/aidl/android/hardware/camera2/ICameraDeviceUser.aidl b/camera/aidl/android/hardware/camera2/ICameraDeviceUser.aidl
index 250f15e..1e8744b 100644
--- a/camera/aidl/android/hardware/camera2/ICameraDeviceUser.aidl
+++ b/camera/aidl/android/hardware/camera2/ICameraDeviceUser.aidl
@@ -36,7 +36,10 @@
* Cancel the repeating request specified by requestId
* Returns the frame number of the last frame that will be produced from this
* repeating request, or NO_IN_FLIGHT_REPEATING_FRAMES if no frames were produced
- * by this repeating request
+ * by this repeating request.
+ *
+ * Repeating request may be stopped by camera device due to an error. Canceling a stopped
+ * repeating request will trigger ERROR_ILLEGAL_ARGUMENT.
*/
long cancelRequest(int requestId);
diff --git a/camera/ndk/impl/ACameraDevice.cpp b/camera/ndk/impl/ACameraDevice.cpp
index 0b758b6..bff5547 100644
--- a/camera/ndk/impl/ACameraDevice.cpp
+++ b/camera/ndk/impl/ACameraDevice.cpp
@@ -380,7 +380,11 @@
int64_t lastFrameNumber;
binder::Status remoteRet = mRemote->cancelRequest(repeatingSequenceId, &lastFrameNumber);
- if (!remoteRet.isOk()) {
+ if (remoteRet.serviceSpecificErrorCode() ==
+ hardware::ICameraService::ERROR_ILLEGAL_ARGUMENT) {
+ ALOGV("Repeating request is already stopped.");
+ return ACAMERA_OK;
+ } else if (!remoteRet.isOk()) {
ALOGE("Stop repeating request fails in remote: %s", remoteRet.toString8().string());
return ACAMERA_ERROR_UNKNOWN;
}
@@ -1342,4 +1346,24 @@
return binder::Status::ok();
}
+binder::Status
+CameraDevice::ServiceCallback::onRepeatingRequestError(int64_t lastFrameNumber) {
+ binder::Status ret = binder::Status::ok();
+
+ sp<CameraDevice> dev = mDevice.promote();
+ if (dev == nullptr) {
+ return ret; // device has been closed
+ }
+
+ Mutex::Autolock _l(dev->mDeviceLock);
+
+ int repeatingSequenceId = dev->mRepeatingSequenceId;
+ dev->mRepeatingSequenceId = REQUEST_ID_NONE;
+
+ dev->checkRepeatingSequenceCompleteLocked(repeatingSequenceId, lastFrameNumber);
+
+ return ret;
+}
+
+
} // namespace android
diff --git a/camera/ndk/impl/ACameraDevice.h b/camera/ndk/impl/ACameraDevice.h
index 3ccf95a..71e364d 100644
--- a/camera/ndk/impl/ACameraDevice.h
+++ b/camera/ndk/impl/ACameraDevice.h
@@ -74,6 +74,7 @@
binder::Status onResultReceived(const CameraMetadata& metadata,
const CaptureResultExtras& resultExtras) override;
binder::Status onPrepared(int streamId) override;
+ binder::Status onRepeatingRequestError(int64_t lastFrameNumber) override;
private:
const wp<CameraDevice> mDevice;
};
diff --git a/camera/tests/CameraBinderTests.cpp b/camera/tests/CameraBinderTests.cpp
index 0b687b4..828a758 100644
--- a/camera/tests/CameraBinderTests.cpp
+++ b/camera/tests/CameraBinderTests.cpp
@@ -149,7 +149,8 @@
PREPARED,
RUNNING,
SENT_RESULT,
- UNINITIALIZED
+ UNINITIALIZED,
+ REPEATING_REQUEST_ERROR,
};
protected:
@@ -215,6 +216,15 @@
return binder::Status::ok();
}
+ virtual binder::Status onRepeatingRequestError(int64_t lastFrameNumber) {
+ (void) lastFrameNumber;
+ Mutex::Autolock l(mLock);
+ mLastStatus = REPEATING_REQUEST_ERROR;
+ mStatusesHit.push_back(mLastStatus);
+ mStatusCondition.broadcast();
+ return binder::Status::ok();
+ }
+
// Test helper functions:
bool hadError() const {
diff --git a/include/media/stagefright/DataSource.h b/include/media/stagefright/DataSource.h
index c5df1f6..0254545 100644
--- a/include/media/stagefright/DataSource.h
+++ b/include/media/stagefright/DataSource.h
@@ -19,7 +19,7 @@
#define DATA_SOURCE_H_
#include <sys/types.h>
-
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/MediaErrors.h>
#include <utils/Errors.h>
#include <utils/KeyedVector.h>
@@ -71,6 +71,20 @@
bool getUInt32(off64_t offset, uint32_t *x);
bool getUInt64(off64_t offset, uint64_t *x);
+ // Reads in "count" entries of type T into vector *x.
+ // Returns true if "count" entries can be read.
+ // If fewer than "count" entries can be read, return false. In this case,
+ // the output vector *x will still have those entries that were read. Call
+ // x->size() to obtain the number of entries read.
+ // The optional parameter chunkSize specifies how many entries should be
+ // read from the data source at one time into a temporary buffer. Increasing
+ // chunkSize can improve the performance at the cost of extra memory usage.
+ // The default value for chunkSize is set to read at least 4k bytes at a
+ // time, depending on sizeof(T).
+ template <typename T>
+ bool getVector(off64_t offset, Vector<T>* x, size_t count,
+ size_t chunkSize = (4095 / sizeof(T)) + 1);
+
// May return ERROR_UNSUPPORTED.
virtual status_t getSize(off64_t *size);
@@ -127,6 +141,51 @@
DataSource &operator=(const DataSource &);
};
+template <typename T>
+bool DataSource::getVector(off64_t offset, Vector<T>* x, size_t count,
+ size_t chunkSize)
+{
+ x->clear();
+ if (chunkSize == 0) {
+ return false;
+ }
+ if (count == 0) {
+ return true;
+ }
+
+ T tmp[chunkSize];
+ ssize_t numBytesRead;
+ size_t numBytesPerChunk = chunkSize * sizeof(T);
+ size_t i;
+
+ for (i = 0; i + chunkSize < count; i += chunkSize) {
+ // This loops is executed when more than chunkSize records need to be
+ // read.
+ numBytesRead = this->readAt(offset, (void*)&tmp, numBytesPerChunk);
+ if (numBytesRead == -1) { // If readAt() returns -1, there is an error.
+ return false;
+ }
+ if (numBytesRead < numBytesPerChunk) {
+ // This case is triggered when the stream ends before the whole
+ // chunk is read.
+ x->appendArray(tmp, (size_t)numBytesRead / sizeof(T));
+ return false;
+ }
+ x->appendArray(tmp, chunkSize);
+ offset += numBytesPerChunk;
+ }
+
+ // There are (count - i) more records to read.
+ // Right now, (count - i) <= chunkSize.
+ // We do the same thing as above, but with chunkSize replaced by count - i.
+ numBytesRead = this->readAt(offset, (void*)&tmp, (count - i) * sizeof(T));
+ if (numBytesRead == -1) {
+ return false;
+ }
+ x->appendArray(tmp, (size_t)numBytesRead / sizeof(T));
+ return x->size() == count;
+}
+
} // namespace android
#endif // DATA_SOURCE_H_
diff --git a/media/libmedia/IMediaExtractor.cpp b/media/libmedia/IMediaExtractor.cpp
index b13b69f..f142ccc 100644
--- a/media/libmedia/IMediaExtractor.cpp
+++ b/media/libmedia/IMediaExtractor.cpp
@@ -216,13 +216,15 @@
return str;
}
-static Vector<ExtractorInstance> extractors;
+static Vector<ExtractorInstance> sExtractors;
+static Mutex sExtractorsLock;
void registerMediaSource(
const sp<IMediaExtractor> &ex,
const sp<IMediaSource> &source) {
- for (size_t i = 0; i < extractors.size(); i++) {
- ExtractorInstance &instance = extractors.editItemAt(i);
+ Mutex::Autolock lock(sExtractorsLock);
+ for (size_t i = 0; i < sExtractors.size(); i++) {
+ ExtractorInstance &instance = sExtractors.editItemAt(i);
sp<IMediaExtractor> extractor = instance.extractor.promote();
if (extractor != NULL && extractor == ex) {
if (instance.tracks.size() > 5) {
@@ -246,19 +248,25 @@
ex.owner = IPCThreadState::self()->getCallingPid();
ex.extractor = extractor;
- if (extractors.size() > 10) {
- extractors.resize(10);
+ {
+ Mutex::Autolock lock(sExtractorsLock);
+ if (sExtractors.size() > 10) {
+ sExtractors.resize(10);
+ }
+ sExtractors.push_front(ex);
}
- extractors.push_front(ex);
}
status_t dumpExtractors(int fd, const Vector<String16>&) {
String8 out;
out.append("Recent extractors, most recent first:\n");
- for (size_t i = 0; i < extractors.size(); i++) {
- const ExtractorInstance &instance = extractors.itemAt(i);
- out.append(" ");
- out.append(instance.toString());
+ {
+ Mutex::Autolock lock(sExtractorsLock);
+ for (size_t i = 0; i < sExtractors.size(); i++) {
+ const ExtractorInstance &instance = sExtractors.itemAt(i);
+ out.append(" ");
+ out.append(instance.toString());
+ }
}
write(fd, out.string(), out.size());
return OK;
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index 7b97d0f..3f7367f 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -1793,6 +1793,7 @@
mWriter.clear();
}
mTotalPausedDurationUs = 0;
+ mPauseStartTimeUs = 0;
mGraphicBufferProducer.clear();
mPersistentSurface.clear();
@@ -1873,7 +1874,6 @@
mTotalBitRate = 0;
mOutputFd = -1;
- mPauseStartTimeUs = 0;
return OK;
}
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index 42a82ac..7b000fa 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -400,14 +400,20 @@
}
void NuPlayer::resetAsync() {
- if (mSource != NULL) {
+ sp<Source> source;
+ {
+ Mutex::Autolock autoLock(mSourceLock);
+ source = mSource;
+ }
+
+ if (source != NULL) {
// During a reset, the data source might be unresponsive already, we need to
// disconnect explicitly so that reads exit promptly.
// We can't queue the disconnect request to the looper, as it might be
// queued behind a stuck read and never gets processed.
// Doing a disconnect outside the looper to allows the pending reads to exit
// (either successfully or with error).
- mSource->disconnect();
+ source->disconnect();
}
(new AMessage(kWhatReset, this))->post();
@@ -484,6 +490,7 @@
sp<RefBase> obj;
CHECK(msg->findObject("source", &obj));
if (obj != NULL) {
+ Mutex::Autolock autoLock(mSourceLock);
mSource = static_cast<Source *>(obj.get());
} else {
err = UNKNOWN_ERROR;
@@ -1998,6 +2005,7 @@
if (mSource != NULL) {
mSource->stop();
+ Mutex::Autolock autoLock(mSourceLock);
mSource.clear();
}
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h
index 369590b..f6eb49e 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h
@@ -140,6 +140,7 @@
bool mUIDValid;
uid_t mUID;
pid_t mPID;
+ Mutex mSourceLock; // guard |mSource|.
sp<Source> mSource;
uint32_t mSourceFlags;
sp<Surface> mSurface;
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index 7a8f4c0..db20590 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -2261,6 +2261,7 @@
HevcParameterSets paramSets;
if (parseHEVCCodecSpecificData(data, size, paramSets) != OK) {
+ ALOGE("failed parsing codec specific data");
return ERROR_MALFORMED;
}
@@ -2271,8 +2272,9 @@
return NO_MEMORY;
}
status_t err = paramSets.makeHvcc((uint8_t *)mCodecSpecificData,
- &mCodecSpecificDataSize, mOwner->useNalLengthFour() ? 5 : 2);
+ &mCodecSpecificDataSize, mOwner->useNalLengthFour() ? 4 : 2);
if (err != OK) {
+ ALOGE("failed constructing HVCC atom");
return err;
}
diff --git a/media/libstagefright/SampleTable.cpp b/media/libstagefright/SampleTable.cpp
index 1bdd812..d92f368 100644
--- a/media/libstagefright/SampleTable.cpp
+++ b/media/libstagefright/SampleTable.cpp
@@ -122,7 +122,7 @@
mDefaultSampleSize(0),
mNumSampleSizes(0),
mTimeToSampleCount(0),
- mTimeToSample(NULL),
+ mTimeToSample(),
mSampleTimeEntries(NULL),
mCompositionTimeDeltaEntries(NULL),
mNumCompositionTimeDeltaEntries(0),
@@ -151,9 +151,6 @@
delete[] mSampleTimeEntries;
mSampleTimeEntries = NULL;
- delete[] mTimeToSample;
- mTimeToSample = NULL;
-
delete mSampleIterator;
mSampleIterator = NULL;
}
@@ -162,7 +159,7 @@
return mChunkOffsetOffset >= 0
&& mSampleToChunkOffset >= 0
&& mSampleSizeOffset >= 0
- && mTimeToSample != NULL;
+ && !mTimeToSample.empty();
}
status_t SampleTable::setChunkOffsetParams(
@@ -336,7 +333,7 @@
status_t SampleTable::setTimeToSampleParams(
off64_t data_offset, size_t data_size) {
- if (mTimeToSample != NULL || data_size < 8) {
+ if (!mTimeToSample.empty() || data_size < 8) {
return ERROR_MALFORMED;
}
@@ -352,24 +349,29 @@
}
mTimeToSampleCount = U32_AT(&header[4]);
- uint64_t allocSize = (uint64_t)mTimeToSampleCount * 2 * sizeof(uint32_t);
- if (allocSize > UINT32_MAX) {
+ if ((uint64_t)mTimeToSampleCount >
+ (uint64_t)UINT32_MAX / (2 * sizeof(uint32_t))) {
+ // Choose this bound because
+ // 1) 2 * sizeof(uint32_t) is the amount of memory needed for one
+ // time-to-sample entry in the time-to-sample table.
+ // 2) mTimeToSampleCount is the number of entries of the time-to-sample
+ // table.
+ // 3) We hope that the table size does not exceed UINT32_MAX.
+ ALOGE(" Error: Time-to-sample table size too large.");
return ERROR_OUT_OF_RANGE;
}
- mTimeToSample = new (std::nothrow) uint32_t[mTimeToSampleCount * 2];
- if (!mTimeToSample)
- return ERROR_OUT_OF_RANGE;
- size_t size = sizeof(uint32_t) * mTimeToSampleCount * 2;
- if (mDataSource->readAt(
- data_offset + 8, mTimeToSample, size) < (ssize_t)size) {
+ // Note: At this point, we know that mTimeToSampleCount * 2 will not
+ // overflow because of the above condition.
+ if (!mDataSource->getVector(data_offset + 8, &mTimeToSample,
+ mTimeToSampleCount * 2)) {
+ ALOGE(" Error: Incomplete data read for time-to-sample table.");
return ERROR_IO;
}
- for (uint32_t i = 0; i < mTimeToSampleCount * 2; ++i) {
- mTimeToSample[i] = ntohl(mTimeToSample[i]);
+ for (size_t i = 0; i < mTimeToSample.size(); ++i) {
+ mTimeToSample.editItemAt(i) = ntohl(mTimeToSample[i]);
}
-
return OK;
}
diff --git a/media/libstagefright/codecs/g711/dec/SoftG711.cpp b/media/libstagefright/codecs/g711/dec/SoftG711.cpp
index 958e7c4..9f7b590 100644
--- a/media/libstagefright/codecs/g711/dec/SoftG711.cpp
+++ b/media/libstagefright/codecs/g711/dec/SoftG711.cpp
@@ -240,6 +240,15 @@
mSignalledError = true;
}
+ if (inHeader->nFilledLen * sizeof(int16_t) > outHeader->nAllocLen) {
+ ALOGE("output buffer too small (%d).", outHeader->nAllocLen);
+ android_errorWriteLog(0x534e4554, "27793163");
+
+ notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
+ mSignalledError = true;
+ return;
+ }
+
const uint8_t *inputptr = inHeader->pBuffer + inHeader->nOffset;
if (mIsMLaw) {
diff --git a/media/libstagefright/codecs/gsm/dec/SoftGSM.cpp b/media/libstagefright/codecs/gsm/dec/SoftGSM.cpp
index 7916c45..04d5a33 100644
--- a/media/libstagefright/codecs/gsm/dec/SoftGSM.cpp
+++ b/media/libstagefright/codecs/gsm/dec/SoftGSM.cpp
@@ -228,6 +228,14 @@
mSignalledError = true;
}
+ if (outHeader->nAllocLen < (inHeader->nFilledLen / kMSGSMFrameSize) * 320) {
+ ALOGE("output buffer is not large enough (%d).", outHeader->nAllocLen);
+ android_errorWriteLog(0x534e4554, "27793367");
+ notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
+ mSignalledError = true;
+ return;
+ }
+
uint8_t *inputptr = inHeader->pBuffer + inHeader->nOffset;
int n = mSignalledError ? 0 : DecodeGSM(mGsm,
diff --git a/media/libstagefright/include/SampleTable.h b/media/libstagefright/include/SampleTable.h
index 738f864..0772eef 100644
--- a/media/libstagefright/include/SampleTable.h
+++ b/media/libstagefright/include/SampleTable.h
@@ -24,6 +24,7 @@
#include <media/stagefright/MediaErrors.h>
#include <utils/RefBase.h>
#include <utils/threads.h>
+#include <utils/Vector.h>
namespace android {
@@ -111,7 +112,7 @@
uint32_t mNumSampleSizes;
uint32_t mTimeToSampleCount;
- uint32_t *mTimeToSample;
+ Vector<uint32_t> mTimeToSample;
struct SampleTimeEntry {
uint32_t mSampleIndex;
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 1b69f8c..d9a19cd 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -176,7 +176,7 @@
mHardwareStatus(AUDIO_HW_IDLE),
mMasterVolume(1.0f),
mMasterMute(false),
- mNextUniqueId(AUDIO_UNIQUE_ID_USE_MAX), // zero has a special meaning, so unavailable
+ // mNextUniqueId(AUDIO_UNIQUE_ID_USE_MAX),
mMode(AUDIO_MODE_INVALID),
mBtNrecIsOff(false),
mIsLowRamDevice(true),
@@ -184,6 +184,12 @@
mGlobalEffectEnableTime(0),
mSystemReady(false)
{
+ // unsigned instead of audio_unique_id_use_t, because ++ operator is unavailable for enum
+ for (unsigned use = AUDIO_UNIQUE_ID_USE_UNSPECIFIED; use < AUDIO_UNIQUE_ID_USE_MAX; use++) {
+ // zero ID has a special meaning, so unavailable
+ mNextUniqueIds[use] = AUDIO_UNIQUE_ID_USE_MAX;
+ }
+
getpid_cached = getpid();
const bool doLog = property_get_bool("ro.test_harness", false);
if (doLog) {
@@ -2440,13 +2446,23 @@
audio_unique_id_t AudioFlinger::nextUniqueId(audio_unique_id_use_t use)
{
- int32_t base = android_atomic_add(AUDIO_UNIQUE_ID_USE_MAX, &mNextUniqueId);
- // We have no way of recovering from wraparound
- LOG_ALWAYS_FATAL_IF(base == 0, "unique ID overflow");
// This is the internal API, so it is OK to assert on bad parameter.
LOG_ALWAYS_FATAL_IF((unsigned) use >= (unsigned) AUDIO_UNIQUE_ID_USE_MAX);
- ALOG_ASSERT(audio_unique_id_get_use(base) == AUDIO_UNIQUE_ID_USE_UNSPECIFIED);
- return (audio_unique_id_t) (base | use);
+ const int maxRetries = use == AUDIO_UNIQUE_ID_USE_SESSION ? 3 : 1;
+ for (int retry = 0; retry < maxRetries; retry++) {
+ // The cast allows wraparound from max positive to min negative instead of abort
+ uint32_t base = (uint32_t) atomic_fetch_add_explicit(&mNextUniqueIds[use],
+ (uint_fast32_t) AUDIO_UNIQUE_ID_USE_MAX, memory_order_acq_rel);
+ ALOG_ASSERT(audio_unique_id_get_use(base) == AUDIO_UNIQUE_ID_USE_UNSPECIFIED);
+ // allow wrap by skipping 0 and -1 for session ids
+ if (!(base == 0 || base == (~0u & ~AUDIO_UNIQUE_ID_USE_MASK))) {
+ ALOGW_IF(retry != 0, "unique ID overflow for use %d", use);
+ return (audio_unique_id_t) (base | use);
+ }
+ }
+ // We have no way of recovering from wraparound
+ LOG_ALWAYS_FATAL("unique ID overflow for use %d", use);
+ // TODO Use a floor after wraparound. This may need a mutex.
}
AudioFlinger::PlaybackThread *AudioFlinger::primaryPlaybackThread_l() const
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 498c33e..5f4b0f1 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -679,9 +679,8 @@
// protected by mClientLock
DefaultKeyedVector< pid_t, sp<NotificationClient> > mNotificationClients;
- volatile int32_t mNextUniqueId; // updated by android_atomic_inc
- // nextUniqueId() returns uint32_t, but this is declared int32_t
- // because the atomic operations require an int32_t
+ // updated by atomic_fetch_add_explicit
+ volatile atomic_uint_fast32_t mNextUniqueIds[AUDIO_UNIQUE_ID_USE_MAX];
audio_mode_t mMode;
bool mBtNrecIsOff;
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 29ab262..fd9587a 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -1857,7 +1857,8 @@
if (!streamsMatchForvolume(stream, (audio_stream_type_t)curStream)) {
continue;
}
- if (!desc->isStreamActive((audio_stream_type_t)curStream)) {
+ if (!(desc->isStreamActive((audio_stream_type_t)curStream) ||
+ (isInCall() && (curStream == AUDIO_STREAM_VOICE_CALL)))) {
continue;
}
routing_strategy curStrategy = getStrategy((audio_stream_type_t)curStream);
@@ -4890,7 +4891,9 @@
float volumeDb = mVolumeCurves->volIndexToDb(stream, Volume::getDeviceCategory(device), index);
// if a headset is connected, apply the following rules to ring tones and notifications
// to avoid sound level bursts in user's ears:
- // - always attenuate ring tones and notifications volume by 6dB
+ // - always attenuate notifications volume by 6dB
+ // - attenuate ring tones volume by 6dB unless music is not playing and
+ // speaker is part of the select devices
// - if music is playing, always limit the volume to current music volume,
// with a minimum threshold at -36dB so that notification is always perceived.
const routing_strategy stream_strategy = getStrategy(stream);
@@ -4904,12 +4907,12 @@
|| ((stream_strategy == STRATEGY_ENFORCED_AUDIBLE) &&
(mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) == AUDIO_POLICY_FORCE_NONE))) &&
mVolumeCurves->canBeMuted(stream)) {
- volumeDb += SONIFICATION_HEADSET_VOLUME_FACTOR_DB;
// when the phone is ringing we must consider that music could have been paused just before
// by the music application and behave as if music was active if the last music track was
// just stopped
if (isStreamActive(AUDIO_STREAM_MUSIC, SONIFICATION_HEADSET_MUSIC_DELAY) ||
mLimitRingtoneVolume) {
+ volumeDb += SONIFICATION_HEADSET_VOLUME_FACTOR_DB;
audio_devices_t musicDevice = getDeviceForStrategy(STRATEGY_MEDIA, true /*fromCache*/);
float musicVolDB = computeVolume(AUDIO_STREAM_MUSIC,
mVolumeCurves->getVolumeIndex(AUDIO_STREAM_MUSIC,
@@ -4921,6 +4924,9 @@
volumeDb = minVolDB;
ALOGV("computeVolume limiting volume to %f musicVol %f", minVolDB, musicVolDB);
}
+ } else if ((Volume::getDeviceForVolume(device) != AUDIO_DEVICE_OUT_SPEAKER) ||
+ stream_strategy != STRATEGY_SONIFICATION) {
+ volumeDb += SONIFICATION_HEADSET_VOLUME_FACTOR_DB;
}
}
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index 94357b9..2d6a873 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -49,10 +49,8 @@
// ----------------------------------------------------------------------------
// Attenuation applied to STRATEGY_SONIFICATION streams when a headset is connected: 6dB
-#define SONIFICATION_HEADSET_VOLUME_FACTOR 0.5
#define SONIFICATION_HEADSET_VOLUME_FACTOR_DB (-6)
// Min volume for STRATEGY_SONIFICATION streams when limited by music volume: -36dB
-#define SONIFICATION_HEADSET_VOLUME_MIN 0.016
#define SONIFICATION_HEADSET_VOLUME_MIN_DB (-36)
// Time in milliseconds during which we consider that music is still active after a music
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index b6c9900..63e44fd 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -75,6 +75,7 @@
Camera2ClientBase(cameraService, remoteCallback, clientPackageName,
cameraId, cameraFacing, clientPid, clientUid, servicePid),
mInputStream(),
+ mStreamingRequestId(REQUEST_ID_NONE),
mRequestIdCounter(0) {
ATRACE_CALL();
@@ -233,7 +234,7 @@
res = STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION,
msg.string());
} else {
- mStreamingRequestList.push_back(submitInfo->mRequestId);
+ mStreamingRequestId = submitInfo->mRequestId;
}
} else {
err = mDevice->captureList(metadataRequestList, &(submitInfo->mLastFrameNumber));
@@ -270,17 +271,9 @@
return STATUS_ERROR(CameraService::ERROR_DISCONNECTED, "Camera device no longer alive");
}
- Vector<int>::iterator it, end;
- for (it = mStreamingRequestList.begin(), end = mStreamingRequestList.end();
- it != end; ++it) {
- if (*it == requestId) {
- break;
- }
- }
-
- if (it == end) {
- String8 msg = String8::format("Camera %d: Did not find request ID %d in list of "
- "streaming requests", mCameraId, requestId);
+ if (mStreamingRequestId != requestId) {
+ String8 msg = String8::format("Camera %d: Canceling request ID %d doesn't match "
+ "current request ID %d", mCameraId, requestId, mStreamingRequestId);
ALOGE("%s: %s", __FUNCTION__, msg.string());
return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
}
@@ -290,7 +283,7 @@
if (err == OK) {
ALOGV("%s: Camera %d: Successfully cleared streaming request",
__FUNCTION__, mCameraId);
- mStreamingRequestList.erase(it);
+ mStreamingRequestId = REQUEST_ID_NONE;
} else {
res = STATUS_ERROR_FMT(CameraService::ERROR_INVALID_OPERATION,
"Camera %d: Error clearing streaming request: %s (%d)",
@@ -767,7 +760,7 @@
}
// FIXME: Also need check repeating burst.
- if (!mStreamingRequestList.isEmpty()) {
+ if (mStreamingRequestId != REQUEST_ID_NONE) {
String8 msg = String8::format(
"Camera %d: Try to waitUntilIdle when there are active streaming requests",
mCameraId);
@@ -799,7 +792,7 @@
return STATUS_ERROR(CameraService::ERROR_DISCONNECTED, "Camera device no longer alive");
}
- mStreamingRequestList.clear();
+ mStreamingRequestId = REQUEST_ID_NONE;
status_t err = mDevice->flush(lastFrameNumber);
if (err != OK) {
res = STATUS_ERROR_FMT(CameraService::ERROR_INVALID_OPERATION,
@@ -982,6 +975,17 @@
}
}
+void CameraDeviceClient::notifyRepeatingRequestError(long lastFrameNumber) {
+ sp<hardware::camera2::ICameraDeviceCallbacks> remoteCb = getRemoteCallback();
+
+ if (remoteCb != 0) {
+ remoteCb->onRepeatingRequestError(lastFrameNumber);
+ }
+
+ Mutex::Autolock icl(mBinderSerializationLock);
+ mStreamingRequestId = REQUEST_ID_NONE;
+}
+
void CameraDeviceClient::notifyIdle() {
// Thread safe. Don't bother locking.
sp<hardware::camera2::ICameraDeviceCallbacks> remoteCb = getRemoteCallback();
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.h b/services/camera/libcameraservice/api2/CameraDeviceClient.h
index 38137a2..3660a18 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.h
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.h
@@ -160,6 +160,7 @@
const CaptureResultExtras& resultExtras);
virtual void notifyShutter(const CaptureResultExtras& resultExtras, nsecs_t timestamp);
virtual void notifyPrepared(int streamId);
+ virtual void notifyRepeatingRequestError(long lastFrameNumber);
/**
* Interface used by independent components of CameraDeviceClient.
@@ -205,8 +206,9 @@
int32_t id;
} mInputStream;
- // Request ID
- Vector<int> mStreamingRequestList;
+ // Streaming request ID
+ int32_t mStreamingRequestId;
+ static const int32_t REQUEST_ID_NONE = -1;
int32_t mRequestIdCounter;
diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.cpp b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
index 2cc150d..c0d6da6 100644
--- a/services/camera/libcameraservice/common/Camera2ClientBase.cpp
+++ b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
@@ -306,6 +306,14 @@
}
template <typename TClientBase>
+void Camera2ClientBase<TClientBase>::notifyRepeatingRequestError(long lastFrameNumber) {
+ (void)lastFrameNumber;
+
+ ALOGV("%s: Repeating request was stopped. Last frame number is %ld",
+ __FUNCTION__, lastFrameNumber);
+}
+
+template <typename TClientBase>
int Camera2ClientBase<TClientBase>::getCameraId() const {
return TClientBase::mCameraId;
}
diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.h b/services/camera/libcameraservice/common/Camera2ClientBase.h
index 6eea2f4..4f60034 100644
--- a/services/camera/libcameraservice/common/Camera2ClientBase.h
+++ b/services/camera/libcameraservice/common/Camera2ClientBase.h
@@ -73,6 +73,7 @@
virtual void notifyAutoWhitebalance(uint8_t newState,
int triggerId);
virtual void notifyPrepared(int streamId);
+ virtual void notifyRepeatingRequestError(long lastFrameNumber);
int getCameraId() const;
const sp<CameraDeviceBase>&
diff --git a/services/camera/libcameraservice/common/CameraDeviceBase.h b/services/camera/libcameraservice/common/CameraDeviceBase.h
index d570d4b..35ec531 100644
--- a/services/camera/libcameraservice/common/CameraDeviceBase.h
+++ b/services/camera/libcameraservice/common/CameraDeviceBase.h
@@ -209,6 +209,7 @@
virtual void notifyAutoExposure(uint8_t newState, int triggerId) = 0;
virtual void notifyAutoWhitebalance(uint8_t newState,
int triggerId) = 0;
+ virtual void notifyRepeatingRequestError(long lastFrameNumber) = 0;
protected:
virtual ~NotificationListener();
};
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index e395935..0de80bd 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -2807,6 +2807,11 @@
status_t Camera3Device::RequestThread::clearRepeatingRequests(/*out*/int64_t *lastFrameNumber) {
Mutex::Autolock l(mRequestLock);
+ return clearRepeatingRequestsLocked(lastFrameNumber);
+
+}
+
+status_t Camera3Device::RequestThread::clearRepeatingRequestsLocked(/*out*/int64_t *lastFrameNumber) {
mRepeatingRequests.clear();
if (lastFrameNumber != NULL) {
*lastFrameNumber = mRepeatingLastFrameNumber;
@@ -2961,6 +2966,22 @@
}
}
+void Camera3Device::RequestThread::checkAndStopRepeatingRequest() {
+ Mutex::Autolock l(mRequestLock);
+ // Check all streams needed by repeating requests are still valid. Otherwise, stop
+ // repeating requests.
+ for (const auto& request : mRepeatingRequests) {
+ for (const auto& s : request->mOutputStreams) {
+ if (s->isAbandoned()) {
+ int64_t lastFrameNumber = 0;
+ clearRepeatingRequestsLocked(&lastFrameNumber);
+ mListener->notifyRepeatingRequestError(lastFrameNumber);
+ return;
+ }
+ }
+ }
+}
+
bool Camera3Device::RequestThread::threadLoop() {
ATRACE_CALL();
status_t res;
@@ -2992,6 +3013,8 @@
if (res == TIMED_OUT) {
// Not a fatal error if getting output buffers time out.
cleanUpFailedRequests(/*sendRequestError*/ true);
+ // Check if any stream is abandoned.
+ checkAndStopRepeatingRequest();
return true;
} else if (res != OK) {
cleanUpFailedRequests(/*sendRequestError*/ false);
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index 349fb4c..0366ef6 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -565,6 +565,9 @@
// ERROR state to mark them as not having valid data. mNextRequests will be cleared.
void cleanUpFailedRequests(bool sendRequestError);
+ // Stop the repeating request if any of its output streams is abandoned.
+ void checkAndStopRepeatingRequest();
+
// Pause handling
bool waitIfPaused();
void unpauseForNewRequests();
@@ -578,6 +581,9 @@
// Handle AE precapture trigger cancel for devices <= CAMERA_DEVICE_API_VERSION_3_2.
void handleAePrecaptureCancelRequest(sp<CaptureRequest> request);
+ // Clear repeating requests. Must be called with mRequestLock held.
+ status_t clearRepeatingRequestsLocked(/*out*/ int64_t *lastFrameNumber = NULL);
+
wp<Camera3Device> mParent;
wp<camera3::StatusTracker> mStatusTracker;
camera3_device_t *mHal3Device;
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
index 1e6452f..d2b98e6 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
@@ -157,6 +157,13 @@
if (res != OK) {
ALOGE("%s: Stream %d: Can't dequeue next output buffer: %s (%d)",
__FUNCTION__, mId, strerror(-res), res);
+
+ // Only transition to STATE_ABANDONED from STATE_CONFIGURED. (If it is STATE_PREPARING,
+ // let prepareNextBuffer handle the error.)
+ if (res == NO_INIT && mState == STATE_CONFIGURED) {
+ mState = STATE_ABANDONED;
+ }
+
return res;
}
}
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.cpp b/services/camera/libcameraservice/device3/Camera3Stream.cpp
index 80dce84..96d62d4 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Stream.cpp
@@ -323,6 +323,11 @@
return mState == STATE_PREPARING;
}
+bool Camera3Stream::isAbandoned() const {
+ Mutex::Autolock l(mLock);
+ return mState == STATE_ABANDONED;
+}
+
status_t Camera3Stream::prepareNextBuffer() {
ATRACE_CALL();
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.h b/services/camera/libcameraservice/device3/Camera3Stream.h
index 810383d..0755700 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.h
+++ b/services/camera/libcameraservice/device3/Camera3Stream.h
@@ -95,6 +95,8 @@
* STATE_PREPARING => STATE_CONFIGURED:
* When sufficient prepareNextBuffer calls have been made to allocate
* all stream buffers, or cancelPrepare is called.
+ * STATE_CONFIGURED => STATE_ABANDONED:
+ * When the buffer queue of the stream is abandoned.
*
* Status Tracking:
* Each stream is tracked by StatusTracker as a separate component,
@@ -353,6 +355,11 @@
void removeBufferListener(
const sp<Camera3StreamBufferListener>& listener);
+ /**
+ * Return if the buffer queue of the stream is abandoned.
+ */
+ bool isAbandoned() const;
+
protected:
const int mId;
/**
@@ -380,7 +387,8 @@
STATE_IN_CONFIG,
STATE_IN_RECONFIG,
STATE_CONFIGURED,
- STATE_PREPARING
+ STATE_PREPARING,
+ STATE_ABANDONED
} mState;
mutable Mutex mLock;
diff --git a/services/camera/libcameraservice/device3/Camera3StreamInterface.h b/services/camera/libcameraservice/device3/Camera3StreamInterface.h
index 3f7e7a7..6cb7a54 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamInterface.h
+++ b/services/camera/libcameraservice/device3/Camera3StreamInterface.h
@@ -262,6 +262,11 @@
virtual status_t disconnect() = 0;
/**
+ * Return if the buffer queue of the stream is abandoned.
+ */
+ virtual bool isAbandoned() const = 0;
+
+ /**
* Debug dump of the stream's state.
*/
virtual void dump(int fd, const Vector<String16> &args) const = 0;