Merge "media: clear pause state at stop()" 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/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/Android.mk b/media/libmediaplayerservice/Android.mk
index 7f41143..edad4be 100644
--- a/media/libmediaplayerservice/Android.mk
+++ b/media/libmediaplayerservice/Android.mk
@@ -32,6 +32,7 @@
libgui \
libmedia \
libmediautils \
+ libmemunreachable \
libsonivox \
libstagefright \
libstagefright_foundation \
@@ -54,6 +55,7 @@
$(TOP)/frameworks/av/include/camera \
$(TOP)/frameworks/native/include/media/openmax \
$(TOP)/external/tremolo/Tremolo \
+ libcore/include \
LOCAL_CFLAGS += -Werror -Wno-error=deprecated-declarations -Wall
LOCAL_CLANG := true
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 424215e..9b081e9 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -62,6 +62,7 @@
#include <media/stagefright/foundation/ALooperRoster.h>
#include <mediautils/BatteryNotifier.h>
+#include <memunreachable/memunreachable.h>
#include <system/audio.h>
#include <private/android_filesystem_config.h>
@@ -536,14 +537,23 @@
gLooperRoster.dump(fd, args);
bool dumpMem = false;
+ bool unreachableMemory = false;
for (size_t i = 0; i < args.size(); i++) {
if (args[i] == String16("-m")) {
dumpMem = true;
+ } else if (args[i] == String16("--unreachable")) {
+ unreachableMemory = true;
}
}
if (dumpMem) {
dumpMemoryAddresses(fd);
}
+ if (unreachableMemory) {
+ result.append("\nDumping unreachable memory:\n");
+ // TODO - should limit be an argument parameter?
+ std::string s = GetUnreachableMemoryString(true /* contents */, 10000 /* limit */);
+ result.append(s.c_str(), s.size());
+ }
}
write(fd, result.string(), result.size());
return NO_ERROR;
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/OggExtractor.cpp b/media/libstagefright/OggExtractor.cpp
index 9162f80..37e8e9c 100644
--- a/media/libstagefright/OggExtractor.cpp
+++ b/media/libstagefright/OggExtractor.cpp
@@ -713,6 +713,7 @@
packetSize);
if (n < (ssize_t)packetSize) {
+ buffer->release();
ALOGV("failed to read %zu bytes at %#016llx, got %zd bytes",
packetSize, (long long)dataOffset, n);
return ERROR_IO;
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/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index fe2f9a6..bf18975 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -1080,8 +1080,16 @@
mOutputRoutes.incRouteActivity(session);
audio_devices_t newDevice;
+ AudioMix *policyMix = NULL;
+ const char *address = NULL;
if (outputDesc->mPolicyMix != NULL) {
- newDevice = AUDIO_DEVICE_OUT_REMOTE_SUBMIX;
+ policyMix = outputDesc->mPolicyMix;
+ address = policyMix->mDeviceAddress.string();
+ if ((policyMix->mRouteFlags & MIX_ROUTE_FLAG_RENDER) == MIX_ROUTE_FLAG_RENDER) {
+ newDevice = policyMix->mDeviceType;
+ } else {
+ newDevice = AUDIO_DEVICE_OUT_REMOTE_SUBMIX;
+ }
} else if (mOutputRoutes.hasRouteChanged(session)) {
newDevice = getNewOutputDevice(outputDesc, false /*fromCache*/);
checkStrategyRoute(getStrategy(stream), output);
@@ -1091,7 +1099,7 @@
uint32_t delayMs = 0;
- status_t status = startSource(outputDesc, stream, newDevice, &delayMs);
+ status_t status = startSource(outputDesc, stream, newDevice, address, &delayMs);
if (status != NO_ERROR) {
mOutputRoutes.decRouteActivity(session);
@@ -1099,11 +1107,11 @@
}
// Automatically enable the remote submix input when output is started on a re routing mix
// of type MIX_TYPE_RECORDERS
- if (audio_is_remote_submix_device(newDevice) && outputDesc->mPolicyMix != NULL &&
- outputDesc->mPolicyMix->mMixType == MIX_TYPE_RECORDERS) {
+ if (audio_is_remote_submix_device(newDevice) && policyMix != NULL &&
+ policyMix->mMixType == MIX_TYPE_RECORDERS) {
setDeviceConnectionStateInt(AUDIO_DEVICE_IN_REMOTE_SUBMIX,
AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
- outputDesc->mPolicyMix->mDeviceAddress,
+ address,
"remote-submix");
}
@@ -1117,6 +1125,7 @@
status_t AudioPolicyManager::startSource(sp<AudioOutputDescriptor> outputDesc,
audio_stream_type_t stream,
audio_devices_t device,
+ const char *address,
uint32_t *delayMs)
{
// cannot start playback of STREAM_TTS if any other output is being used
@@ -1173,7 +1182,7 @@
}
}
}
- uint32_t muteWaitMs = setOutputDevice(outputDesc, device, force);
+ uint32_t muteWaitMs = setOutputDevice(outputDesc, device, force, 0, NULL, address);
// handle special case for sonification while in call
if (isInCall()) {
@@ -1848,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);
@@ -2097,7 +2107,6 @@
&& (patch->mPatch.sinks[0].ext.device.type == device)
&& (strncmp(patch->mPatch.sinks[0].ext.device.address, address.string(),
AUDIO_DEVICE_MAX_ADDRESS_LEN) == 0)) {
-
if (mPolicyMixes.registerMix(address, mixes[i], desc) != NO_ERROR) {
res = INVALID_OPERATION;
} else {
@@ -2976,7 +2985,7 @@
return INVALID_OPERATION;
}
uint32_t delayMs = 0;
- status = startSource(outputDesc, stream, sinkDevice, &delayMs);
+ status = startSource(outputDesc, stream, sinkDevice, NULL, &delayMs);
if (status != NO_ERROR) {
mpClientInterface->releaseAudioPatch(sourceDesc->mPatchDesc->mAfPatchHandle, 0);
@@ -3200,6 +3209,10 @@
}
sp<SwAudioOutputDescriptor> outputDesc = new SwAudioOutputDescriptor(outProfile,
mpClientInterface);
+ const DeviceVector &supportedDevices = outProfile->getSupportedDevices();
+ const DeviceVector &devicesForType = supportedDevices.getDevicesFromType(profileType);
+ String8 address = devicesForType.size() > 0 ? devicesForType.itemAt(0)->mAddress
+ : String8("");
outputDesc->mDevice = profileType;
audio_config_t config = AUDIO_CONFIG_INITIALIZER;
@@ -3211,7 +3224,7 @@
&output,
&config,
&outputDesc->mDevice,
- String8(""),
+ address,
&outputDesc->mLatency,
outputDesc->mFlags);
@@ -3224,7 +3237,6 @@
outputDesc->mChannelMask = config.channel_mask;
outputDesc->mFormat = config.format;
- const DeviceVector &supportedDevices = outProfile->getSupportedDevices();
for (size_t k = 0; k < supportedDevices.size(); k++) {
ssize_t index = mAvailableOutputDevices.indexOf(supportedDevices[k]);
// give a valid ID to an attached device once confirmed it is reachable
@@ -3239,7 +3251,10 @@
addOutput(output, outputDesc);
setOutputDevice(outputDesc,
outputDesc->mDevice,
- true);
+ true,
+ 0,
+ NULL,
+ address.string());
}
}
// open input streams needed to access attached devices to validate
@@ -4614,9 +4629,13 @@
if (device == AUDIO_DEVICE_NONE) {
resetOutputDevice(outputDesc, delayMs, NULL);
} else {
- DeviceVector deviceList = (address == NULL) ?
- mAvailableOutputDevices.getDevicesFromType(device)
- : mAvailableOutputDevices.getDevicesFromTypeAddr(device, String8(address));
+ DeviceVector deviceList;
+ if ((address == NULL) || (strlen(address) == 0)) {
+ deviceList = mAvailableOutputDevices.getDevicesFromType(device);
+ } else {
+ deviceList = mAvailableOutputDevices.getDevicesFromTypeAddr(device, String8(address));
+ }
+
if (!deviceList.isEmpty()) {
struct audio_patch patch;
outputDesc->toAudioPortConfig(&patch.sources[0]);
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index 0420679..94357b9 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -484,6 +484,7 @@
status_t startSource(sp<AudioOutputDescriptor> outputDesc,
audio_stream_type_t stream,
audio_devices_t device,
+ const char *address,
uint32_t *delayMs);
status_t stopSource(sp<AudioOutputDescriptor> outputDesc,
audio_stream_type_t stream,
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;