ProCamera: Add CpuConsumer asynchronous mode support

Bug: 8290146
Bug: 8291751
Change-Id: I25423a2b8a70ac7169911b1c7b482aa17190fe0f
diff --git a/camera/ProCamera.cpp b/camera/ProCamera.cpp
index 13ba07c..3cfabf6 100644
--- a/camera/ProCamera.cpp
+++ b/camera/ProCamera.cpp
@@ -241,6 +241,17 @@
                                     int heapCount,
                                     /*out*/
                                     sp<CpuConsumer>* cpuConsumer,
+                                    int* streamId) {
+    return createStreamCpu(width, height, format, heapCount,
+                           /*synchronousMode*/true,
+                           cpuConsumer, streamId);
+}
+
+status_t ProCamera::createStreamCpu(int width, int height, int format,
+                                    int heapCount,
+                                    bool synchronousMode,
+                                    /*out*/
+                                    sp<CpuConsumer>* cpuConsumer,
                                     int* streamId)
 {
     ALOGV("%s: createStreamW %dx%d (fmt=0x%x)", __FUNCTION__, width, height,
@@ -251,7 +262,7 @@
     sp <IProCameraUser> c = mCamera;
     if (c == 0) return NO_INIT;
 
-    sp<CpuConsumer> cc = new CpuConsumer(heapCount);
+    sp<CpuConsumer> cc = new CpuConsumer(heapCount, synchronousMode);
     cc->setName(String8("ProCamera::mCpuConsumer"));
 
     sp<Surface> stc = new Surface(
@@ -272,6 +283,7 @@
 
     getStreamInfo(*streamId).cpuStream = true;
     getStreamInfo(*streamId).cpuConsumer = cc;
+    getStreamInfo(*streamId).synchronousMode = synchronousMode;
     getStreamInfo(*streamId).stc = stc;
     // for lifetime management
     getStreamInfo(*streamId).frameAvailableListener = frameAvailableListener;
@@ -373,6 +385,13 @@
         return BAD_VALUE;
     }
 
+    if (!si.synchronousMode) {
+        ALOGW("%s: No need to drop frames on asynchronous streams,"
+              " as asynchronous mode only keeps 1 latest frame around.",
+              __FUNCTION__);
+        return BAD_VALUE;
+    }
+
     int numDropped = 0;
     for (int i = 0; i < count; ++i) {
         CpuConsumer::LockedBuffer buffer;
diff --git a/camera/tests/ProCameraTests.cpp b/camera/tests/ProCameraTests.cpp
index c61e71a..1a8564e 100644
--- a/camera/tests/ProCameraTests.cpp
+++ b/camera/tests/ProCameraTests.cpp
@@ -1061,7 +1061,7 @@
     EXPECT_OK(mCamera->exclusiveUnlock());
 }
 
-TEST_F(ProCameraTest, WaitForSingleStreamBufferAndDropFrames) {
+TEST_F(ProCameraTest, WaitForSingleStreamBufferAndDropFramesSync) {
     if (HasFatalFailure()) {
         return;
     }
@@ -1071,7 +1071,8 @@
     int streamId = -1;
     sp<CpuConsumer> consumer;
     EXPECT_OK(mCamera->createStreamCpu(/*width*/1280, /*height*/960,
-                  TEST_FORMAT_MAIN, TEST_CPU_HEAP_COUNT, &consumer, &streamId));
+                  TEST_FORMAT_MAIN, TEST_CPU_HEAP_COUNT,
+                  /*synchronousMode*/true, &consumer, &streamId));
     EXPECT_NE(-1, streamId);
 
     EXPECT_OK(mCamera->exclusiveTryLock());
@@ -1114,6 +1115,57 @@
     EXPECT_OK(mCamera->exclusiveUnlock());
 }
 
+TEST_F(ProCameraTest, WaitForSingleStreamBufferAndDropFramesAsync) {
+    if (HasFatalFailure()) {
+        return;
+    }
+
+    const int NUM_REQUESTS = 20 * TEST_CPU_FRAME_COUNT;
+
+    int streamId = -1;
+    sp<CpuConsumer> consumer;
+    EXPECT_OK(mCamera->createStreamCpu(/*width*/1280, /*height*/960,
+                  TEST_FORMAT_MAIN, TEST_CPU_HEAP_COUNT,
+                  /*synchronousMode*/false, &consumer, &streamId));
+    EXPECT_NE(-1, streamId);
+
+    EXPECT_OK(mCamera->exclusiveTryLock());
+
+    uint8_t streams[] = { streamId };
+    ASSERT_NO_FATAL_FAILURE(createSubmitRequestForStreams(streams, /*count*/1,
+                                                     /*requests*/NUM_REQUESTS));
+
+    // Consume a couple of results
+    for (int i = 0; i < NUM_REQUESTS; ++i) {
+        int numFrames;
+        EXPECT_TRUE((numFrames = mCamera->waitForFrameBuffer(streamId)) > 0);
+
+        dout << "Dropped " << (numFrames - 1) << " frames" << std::endl;
+
+        // Skip the counter ahead, don't try to consume these frames again
+        i += numFrames-1;
+
+        // "Consume" the buffer
+        CpuConsumer::LockedBuffer buf;
+        EXPECT_OK(consumer->lockNextBuffer(&buf));
+
+        dout << "Buffer asynchronously received on streamId = " << streamId <<
+                ", dataPtr = " << (void*)buf.data <<
+                ", timestamp = " << buf.timestamp << std::endl;
+
+        // Process at 10fps, stream is at 15fps.
+        // This means we will definitely fill up the buffer queue with
+        // extra buffers and need to drop them.
+        usleep(TEST_FRAME_PROCESSING_DELAY_US);
+
+        EXPECT_OK(consumer->unlockBuffer(buf));
+    }
+
+    // Done: clean up
+    EXPECT_OK(mCamera->deleteStream(streamId));
+    EXPECT_OK(mCamera->exclusiveUnlock());
+}
+
 
 
 //TODO: refactor into separate file