CameraNdk: add onBufferLost capture callback

Bug: 27102995
Change-Id: Ic54d1950da54c09eb2fea1eea5fccd3141c626d4
diff --git a/camera/ndk/impl/ACameraDevice.cpp b/camera/ndk/impl/ACameraDevice.cpp
index 8f1115a..fa69727 100644
--- a/camera/ndk/impl/ACameraDevice.cpp
+++ b/camera/ndk/impl/ACameraDevice.cpp
@@ -18,7 +18,6 @@
 #define LOG_TAG "ACameraDevice"
 
 #include <vector>
-#include <utility>
 #include <inttypes.h>
 #include <android/hardware/ICameraService.h>
 #include <camera2/SubmitInfo.h>
@@ -43,6 +42,7 @@
 const char* CameraDevice::kCaptureFailureKey = "CaptureFailure";
 const char* CameraDevice::kSequenceIdKey     = "SequenceId";
 const char* CameraDevice::kFrameNumberKey    = "FrameNumber";
+const char* CameraDevice::kAnwKey            = "Anw";
 
 /**
  * CameraDevice Implementation
@@ -465,10 +465,9 @@
 }
 
 camera_status_t
-CameraDevice::getIGBPfromSessionOutput(
-        const ACaptureSessionOutput& config,
+CameraDevice::getIGBPfromAnw(
+        ANativeWindow* anw,
         sp<IGraphicBufferProducer>& out) {
-    ANativeWindow* anw = config.mWindow;
     if (anw == nullptr) {
         ALOGE("Error: output ANativeWindow is null");
         return ACAMERA_ERROR_INVALID_PARAMETER;
@@ -514,26 +513,28 @@
         return ret;
     }
 
-    std::set<OutputConfiguration> outputSet;
+    std::set<std::pair<ANativeWindow*, OutputConfiguration>> outputSet;
     for (auto outConfig : outputs->mOutputs) {
+        ANativeWindow* anw = outConfig.mWindow;
         sp<IGraphicBufferProducer> iGBP(nullptr);
-        ret = getIGBPfromSessionOutput(outConfig, iGBP);
+        ret = getIGBPfromAnw(anw, iGBP);
         if (ret != ACAMERA_OK) {
             return ret;
         }
-        outputSet.insert(OutputConfiguration(iGBP, outConfig.mRotation));
+        outputSet.insert(std::make_pair(
+                anw, OutputConfiguration(iGBP, outConfig.mRotation)));
     }
-    std::set<OutputConfiguration> addSet = outputSet;
+    auto addSet = outputSet;
     std::vector<int> deleteList;
 
     // Determine which streams need to be created, which to be deleted
     for (auto& kvPair : mConfiguredOutputs) {
         int streamId = kvPair.first;
-        OutputConfiguration& outConfig = kvPair.second;
-        if (outputSet.count(outConfig) == 0) {
+        auto& outputPair = kvPair.second;
+        if (outputSet.count(outputPair) == 0) {
             deleteList.push_back(streamId); // Need to delete a no longer needed stream
         } else {
-            addSet.erase(outConfig);        // No need to add already existing stream
+            addSet.erase(outputPair);        // No need to add already existing stream
         }
     }
 
@@ -585,15 +586,15 @@
     }
 
     // add new streams
-    for (auto outConfig : addSet) {
+    for (auto outputPair : addSet) {
         int streamId;
-        remoteRet = mRemote->createStream(outConfig, &streamId);
+        remoteRet = mRemote->createStream(outputPair.second, &streamId);
         if (!remoteRet.isOk()) {
             ALOGE("Camera device %s failed to create stream: %s", getId(),
                     remoteRet.toString8().string());
             return ACAMERA_ERROR_UNKNOWN;
         }
-        mConfiguredOutputs.insert(std::make_pair(streamId, outConfig));
+        mConfiguredOutputs.insert(std::make_pair(streamId, outputPair));
     }
 
     remoteRet = mRemote->endConfigure(/*isConstrainedHighSpeed*/ false);
@@ -682,26 +683,51 @@
     int sequenceId = resultExtras.requestId;
     int64_t frameNumber = resultExtras.frameNumber;
     int32_t burstId = resultExtras.burstId;
-
-    // No way to report buffer error now
-    if (errorCode == hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_BUFFER) {
-        ALOGE("Camera %s Lost output buffer for frame %" PRId64,
-                getId(), frameNumber);
+    auto it = mSequenceCallbackMap.find(sequenceId);
+    if (it == mSequenceCallbackMap.end()) {
+        ALOGE("%s: Error: capture sequence index %d not found!",
+                __FUNCTION__, sequenceId);
+        setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_SERVICE);
         return;
     }
-    // Fire capture failure callback if there is one registered
-    auto it = mSequenceCallbackMap.find(sequenceId);
-    if (it != mSequenceCallbackMap.end()) {
-        CallbackHolder cbh = (*it).second;
-        ACameraCaptureSession_captureCallback_failed onError = cbh.mCallbacks.onCaptureFailed;
-        sp<ACameraCaptureSession> session = cbh.mSession;
-        if ((size_t) burstId >= cbh.mRequests.size()) {
-            ALOGE("%s: Error: request index %d out of bound (size %zu)",
-                    __FUNCTION__, burstId, cbh.mRequests.size());
+
+    CallbackHolder cbh = (*it).second;
+    sp<ACameraCaptureSession> session = cbh.mSession;
+    if ((size_t) burstId >= cbh.mRequests.size()) {
+        ALOGE("%s: Error: request index %d out of bound (size %zu)",
+                __FUNCTION__, burstId, cbh.mRequests.size());
+        setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_SERVICE);
+        return;
+    }
+    sp<CaptureRequest> request = cbh.mRequests[burstId];
+
+    // Handle buffer error
+    if (errorCode == hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_BUFFER) {
+        int32_t streamId = resultExtras.errorStreamId;
+        ACameraCaptureSession_captureCallback_bufferLost onBufferLost =
+                cbh.mCallbacks.onCaptureBufferLost;
+        auto outputPairIt = mConfiguredOutputs.find(streamId);
+        if (outputPairIt == mConfiguredOutputs.end()) {
+            ALOGE("%s: Error: stream id %d does not exist", __FUNCTION__, streamId);
             setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_SERVICE);
             return;
         }
-        sp<CaptureRequest> request = cbh.mRequests[burstId];
+        ANativeWindow* anw = outputPairIt->second.first;
+
+        ALOGV("Camera %s Lost output buffer for ANW %p frame %" PRId64,
+                getId(), anw, frameNumber);
+
+        sp<AMessage> msg = new AMessage(kWhatCaptureBufferLost, mHandler);
+        msg->setPointer(kContextKey, cbh.mCallbacks.context);
+        msg->setObject(kSessionSpKey, session);
+        msg->setPointer(kCallbackFpKey, (void*) onBufferLost);
+        msg->setObject(kCaptureRequestKey, request);
+        msg->setPointer(kAnwKey, (void*) anw);
+        msg->setInt64(kFrameNumberKey, frameNumber);
+        msg->post();
+    } else { // Handle other capture failures
+        // Fire capture failure callback if there is one registered
+        ACameraCaptureSession_captureCallback_failed onError = cbh.mCallbacks.onCaptureFailed;
         sp<CameraCaptureFailure> failure(new CameraCaptureFailure());
         failure->frameNumber = frameNumber;
         // TODO: refine this when implementing flush
@@ -717,11 +743,12 @@
         msg->setObject(kCaptureRequestKey, request);
         msg->setObject(kCaptureFailureKey, failure);
         msg->post();
-    }
 
-    // Update tracker
-    mFrameNumberTracker.updateTracker(frameNumber, /*isError*/true);
-    checkAndFireSequenceCompleteLocked();
+        // Update tracker
+        mFrameNumberTracker.updateTracker(frameNumber, /*isError*/true);
+        checkAndFireSequenceCompleteLocked();
+    }
+    return;
 }
 
 void CameraDevice::CallbackHandler::onMessageReceived(
@@ -735,6 +762,7 @@
         case kWhatCaptureFail:
         case kWhatCaptureSeqEnd:
         case kWhatCaptureSeqAbort:
+        case kWhatCaptureBufferLost:
             ALOGV("%s: Received msg %d", __FUNCTION__, msg->what());
             break;
         default:
@@ -801,6 +829,7 @@
         case kWhatCaptureFail:
         case kWhatCaptureSeqEnd:
         case kWhatCaptureSeqAbort:
+        case kWhatCaptureBufferLost:
         {
             sp<RefBase> obj;
             found = msg->findObject(kSessionSpKey, &obj);
@@ -814,6 +843,7 @@
                 case kWhatCaptureStart:
                 case kWhatCaptureResult:
                 case kWhatCaptureFail:
+                case kWhatCaptureBufferLost:
                     found = msg->findObject(kCaptureRequestKey, &obj);
                     if (!found) {
                         ALOGE("%s: Cannot find capture request!", __FUNCTION__);
@@ -956,6 +986,37 @@
                     (*onSeqAbort)(context, session.get(), seqId);
                     break;
                 }
+                case kWhatCaptureBufferLost:
+                {
+                    ACameraCaptureSession_captureCallback_bufferLost onBufferLost;
+                    found = msg->findPointer(kCallbackFpKey, (void**) &onBufferLost);
+                    if (!found) {
+                        ALOGE("%s: Cannot find buffer lost callback!", __FUNCTION__);
+                        return;
+                    }
+                    if (onBufferLost == nullptr) {
+                        return;
+                    }
+
+                    ANativeWindow* anw;
+                    found = msg->findPointer(kAnwKey, (void**) &anw);
+                    if (!found) {
+                        ALOGE("%s: Cannot find ANativeWindow!", __FUNCTION__);
+                        return;
+                    }
+
+                    int64_t frameNumber;
+                    found = msg->findInt64(kFrameNumberKey, &frameNumber);
+                    if (!found) {
+                        ALOGE("%s: Cannot find frame number!", __FUNCTION__);
+                        return;
+                    }
+
+                    ACaptureRequest* request = allocateACaptureRequest(requestSp);
+                    (*onBufferLost)(context, session.get(), request, anw, frameNumber);
+                    freeACaptureRequest(request);
+                    break;
+                }
             }
             break;
         }
diff --git a/camera/ndk/impl/ACameraDevice.h b/camera/ndk/impl/ACameraDevice.h
index fd51a81..3ccf95a 100644
--- a/camera/ndk/impl/ACameraDevice.h
+++ b/camera/ndk/impl/ACameraDevice.h
@@ -20,6 +20,7 @@
 #include <map>
 #include <set>
 #include <atomic>
+#include <utility>
 #include <utils/StrongPointer.h>
 #include <utils/Mutex.h>
 #include <utils/String8.h>
@@ -134,8 +135,8 @@
 
     camera_status_t configureStreamsLocked(const ACaptureSessionOutputContainer* outputs);
 
-    static camera_status_t getIGBPfromSessionOutput(
-            const ACaptureSessionOutput& config, sp<IGraphicBufferProducer>& out);
+    static camera_status_t getIGBPfromAnw(
+            ANativeWindow* anw, sp<IGraphicBufferProducer>& out);
 
     static camera_status_t getSurfaceFromANativeWindow(
             ANativeWindow* anw, sp<Surface>& out);
@@ -147,8 +148,8 @@
     const sp<ServiceCallback> mServiceCallback;
     ACameraDevice* mWrapper;
 
-    // stream id -> OutputConfiguration map
-    std::map<int, OutputConfiguration> mConfiguredOutputs;
+    // stream id -> pair of (ANW* from application, OutputConfiguration used for camera service)
+    std::map<int, std::pair<ANativeWindow*, OutputConfiguration>> mConfiguredOutputs;
 
     // TODO: maybe a bool will suffice for synchronous implementation?
     std::atomic_bool mClosing;
@@ -171,16 +172,17 @@
     // definition of handler and message
     enum {
         // Device state callbacks
-        kWhatOnDisconnected, // onDisconnected
-        kWhatOnError,        // onError
+        kWhatOnDisconnected,   // onDisconnected
+        kWhatOnError,          // onError
         // Session state callbacks
-        kWhatSessionStateCb, // onReady, onActive
+        kWhatSessionStateCb,   // onReady, onActive
         // Capture callbacks
-        kWhatCaptureStart,   // onCaptureStarted
-        kWhatCaptureResult,  // onCaptureProgressed, onCaptureCompleted
-        kWhatCaptureFail,    // onCaptureFailed
-        kWhatCaptureSeqEnd,  // onCaptureSequenceCompleted
-        kWhatCaptureSeqAbort // onCaptureSequenceAborted
+        kWhatCaptureStart,     // onCaptureStarted
+        kWhatCaptureResult,    // onCaptureProgressed, onCaptureCompleted
+        kWhatCaptureFail,      // onCaptureFailed
+        kWhatCaptureSeqEnd,    // onCaptureSequenceCompleted
+        kWhatCaptureSeqAbort,  // onCaptureSequenceAborted
+        kWhatCaptureBufferLost // onCaptureBufferLost
     };
     static const char* kContextKey;
     static const char* kDeviceKey;
@@ -193,6 +195,7 @@
     static const char* kCaptureFailureKey;
     static const char* kSequenceIdKey;
     static const char* kFrameNumberKey;
+    static const char* kAnwKey;
     class CallbackHandler : public AHandler {
       public:
         CallbackHandler() {}
@@ -227,7 +230,7 @@
             if (cbs != nullptr) {
                 return *cbs;
             }
-            return { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr };
+            return { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr };
         }
 
         sp<ACameraCaptureSession>   mSession;