Register resource observer and handle resource lost.

bug: 168307955
bug: 154733526
Change-Id: I2d5e39ce23bc873dd3bac090e3f7aa1124d0a579
diff --git a/media/libmediatranscoding/TranscoderWrapper.cpp b/media/libmediatranscoding/TranscoderWrapper.cpp
index bd03671..8062fcf 100644
--- a/media/libmediatranscoding/TranscoderWrapper.cpp
+++ b/media/libmediatranscoding/TranscoderWrapper.cpp
@@ -89,26 +89,40 @@
 }
 
 //static
-const char* TranscoderWrapper::toString(Event::Type type) {
-    switch (type) {
+std::string TranscoderWrapper::toString(const Event& event) {
+    std::string typeStr;
+    switch (event.type) {
     case Event::Start:
-        return "Start";
-    case Event::Pause:
-        return "Pause";
-    case Event::Resume:
-        return "Resume";
-    case Event::Stop:
-        return "Stop";
-    case Event::Finish:
-        return "Finish";
-    case Event::Error:
-        return "Error";
-    case Event::Progress:
-        return "Progress";
-    default:
+        typeStr = "Start";
         break;
+    case Event::Pause:
+        typeStr = "Pause";
+        break;
+    case Event::Resume:
+        typeStr = "Resume";
+        break;
+    case Event::Stop:
+        typeStr = "Stop";
+        break;
+    case Event::Finish:
+        typeStr = "Finish";
+        break;
+    case Event::Error:
+        typeStr = "Error";
+        break;
+    case Event::Progress:
+        typeStr = "Progress";
+        break;
+    default:
+        return "(unknown)";
     }
-    return "(unknown)";
+    std::string result;
+    result = "job {" + std::to_string(event.clientId) + "," + std::to_string(event.jobId) +
+             "}: " + typeStr;
+    if (event.type == Event::Error || event.type == Event::Progress) {
+        result += " " + std::to_string(event.arg);
+    }
+    return result;
 }
 
 class TranscoderWrapper::CallbackImpl : public MediaTranscoder::CallbackInterface {
@@ -128,7 +142,7 @@
                          media_status_t error) override {
         auto owner = mOwner.lock();
         if (owner != nullptr) {
-            owner->onError(mClientId, mJobId, toTranscodingError(error));
+            owner->onError(mClientId, mJobId, error);
         }
     }
 
@@ -160,20 +174,41 @@
     mCallback = cb;
 }
 
+static bool isResourceError(media_status_t err) {
+    return err == AMEDIACODEC_ERROR_RECLAIMED || err == AMEDIACODEC_ERROR_INSUFFICIENT_RESOURCE;
+}
+
+void TranscoderWrapper::reportError(ClientIdType clientId, JobIdType jobId, media_status_t err) {
+    auto callback = mCallback.lock();
+    if (callback != nullptr) {
+        if (isResourceError(err)) {
+            // Add a placeholder pause state to mPausedStateMap. This is required when resuming.
+            // TODO: remove this when transcoder pause/resume logic is ready. New logic will
+            // no longer use the pause states.
+            auto it = mPausedStateMap.find(JobKeyType(clientId, jobId));
+            if (it == mPausedStateMap.end()) {
+                mPausedStateMap.emplace(JobKeyType(clientId, jobId),
+                                        std::shared_ptr<const Parcel>());
+            }
+
+            callback->onResourceLost();
+        } else {
+            callback->onError(clientId, jobId, toTranscodingError(err));
+        }
+    }
+}
+
 void TranscoderWrapper::start(ClientIdType clientId, JobIdType jobId,
                               const TranscodingRequestParcel& request,
                               const std::shared_ptr<ITranscodingClientCallback>& clientCb) {
     queueEvent(Event::Start, clientId, jobId, [=] {
-        TranscodingErrorCode err = handleStart(clientId, jobId, request, clientCb);
+        media_status_t err = handleStart(clientId, jobId, request, clientCb);
 
-        auto callback = mCallback.lock();
-        if (err != TranscodingErrorCode::kNoError) {
+        if (err != AMEDIA_OK) {
             cleanup();
-
-            if (callback != nullptr) {
-                callback->onError(clientId, jobId, err);
-            }
+            reportError(clientId, jobId, err);
         } else {
+            auto callback = mCallback.lock();
             if (callback != nullptr) {
                 callback->onStarted(clientId, jobId);
             }
@@ -183,15 +218,15 @@
 
 void TranscoderWrapper::pause(ClientIdType clientId, JobIdType jobId) {
     queueEvent(Event::Pause, clientId, jobId, [=] {
-        TranscodingErrorCode err = handlePause(clientId, jobId);
+        media_status_t err = handlePause(clientId, jobId);
 
         cleanup();
 
-        auto callback = mCallback.lock();
-        if (callback != nullptr) {
-            if (err != TranscodingErrorCode::kNoError) {
-                callback->onError(clientId, jobId, err);
-            } else {
+        if (err != AMEDIA_OK) {
+            reportError(clientId, jobId, err);
+        } else {
+            auto callback = mCallback.lock();
+            if (callback != nullptr) {
                 callback->onPaused(clientId, jobId);
             }
         }
@@ -202,16 +237,13 @@
                                const TranscodingRequestParcel& request,
                                const std::shared_ptr<ITranscodingClientCallback>& clientCb) {
     queueEvent(Event::Resume, clientId, jobId, [=] {
-        TranscodingErrorCode err = handleResume(clientId, jobId, request, clientCb);
+        media_status_t err = handleResume(clientId, jobId, request, clientCb);
 
-        auto callback = mCallback.lock();
-        if (err != TranscodingErrorCode::kNoError) {
+        if (err != AMEDIA_OK) {
             cleanup();
-
-            if (callback != nullptr) {
-                callback->onError(clientId, jobId, err);
-            }
+            reportError(clientId, jobId, err);
         } else {
+            auto callback = mCallback.lock();
             if (callback != nullptr) {
                 callback->onResumed(clientId, jobId);
             }
@@ -225,7 +257,7 @@
             // Cancelling the currently running job.
             media_status_t err = mTranscoder->cancel();
             if (err != AMEDIA_OK) {
-                ALOGE("failed to stop transcoder: %d", err);
+                ALOGW("failed to stop transcoder: %d", err);
             } else {
                 ALOGI("transcoder stopped");
             }
@@ -251,41 +283,43 @@
     });
 }
 
-void TranscoderWrapper::onError(ClientIdType clientId, JobIdType jobId,
-                                TranscodingErrorCode error) {
-    queueEvent(Event::Error, clientId, jobId, [=] {
-        if (mTranscoder != nullptr && clientId == mCurrentClientId && jobId == mCurrentJobId) {
-            cleanup();
-        }
-
-        auto callback = mCallback.lock();
-        if (callback != nullptr) {
-            callback->onError(clientId, jobId, error);
-        }
-    });
+void TranscoderWrapper::onError(ClientIdType clientId, JobIdType jobId, media_status_t error) {
+    queueEvent(
+            Event::Error, clientId, jobId,
+            [=] {
+                if (mTranscoder != nullptr && clientId == mCurrentClientId &&
+                    jobId == mCurrentJobId) {
+                    cleanup();
+                }
+                reportError(clientId, jobId, error);
+            },
+            error);
 }
 
 void TranscoderWrapper::onProgress(ClientIdType clientId, JobIdType jobId, int32_t progress) {
-    queueEvent(Event::Progress, clientId, jobId, [=] {
-        auto callback = mCallback.lock();
-        if (callback != nullptr) {
-            callback->onProgressUpdate(clientId, jobId, progress);
-        }
-    });
+    queueEvent(
+            Event::Progress, clientId, jobId,
+            [=] {
+                auto callback = mCallback.lock();
+                if (callback != nullptr) {
+                    callback->onProgressUpdate(clientId, jobId, progress);
+                }
+            },
+            progress);
 }
 
-TranscodingErrorCode TranscoderWrapper::setupTranscoder(
+media_status_t TranscoderWrapper::setupTranscoder(
         ClientIdType clientId, JobIdType jobId, const TranscodingRequestParcel& request,
         const std::shared_ptr<ITranscodingClientCallback>& clientCb,
         const std::shared_ptr<const Parcel>& pausedState) {
     if (clientCb == nullptr) {
         ALOGE("client callback is null");
-        return TranscodingErrorCode::kInvalidParameter;
+        return AMEDIA_ERROR_INVALID_PARAMETER;
     }
 
     if (mTranscoder != nullptr) {
         ALOGE("transcoder already running");
-        return TranscodingErrorCode::kInvalidOperation;
+        return AMEDIA_ERROR_INVALID_OPERATION;
     }
 
     Status status;
@@ -293,7 +327,7 @@
     status = clientCb->openFileDescriptor(request.sourceFilePath, "r", &srcFd);
     if (!status.isOk() || srcFd.get() < 0) {
         ALOGE("failed to open source");
-        return TranscodingErrorCode::kErrorIO;
+        return AMEDIA_ERROR_IO;
     }
 
     // Open dest file with "rw", as the transcoder could potentially reuse part of it
@@ -302,7 +336,7 @@
     status = clientCb->openFileDescriptor(request.destinationFilePath, "rw", &dstFd);
     if (!status.isOk() || dstFd.get() < 0) {
         ALOGE("failed to open destination");
-        return TranscodingErrorCode::kErrorIO;
+        return AMEDIA_ERROR_IO;
     }
 
     mCurrentClientId = clientId;
@@ -311,19 +345,19 @@
     mTranscoder = MediaTranscoder::create(mTranscoderCb, pausedState);
     if (mTranscoder == nullptr) {
         ALOGE("failed to create transcoder");
-        return TranscodingErrorCode::kUnknown;
+        return AMEDIA_ERROR_UNKNOWN;
     }
 
     media_status_t err = mTranscoder->configureSource(srcFd.get());
     if (err != AMEDIA_OK) {
         ALOGE("failed to configure source: %d", err);
-        return toTranscodingError(err);
+        return err;
     }
 
     std::vector<std::shared_ptr<AMediaFormat>> trackFormats = mTranscoder->getTrackFormats();
     if (trackFormats.size() == 0) {
         ALOGE("failed to get track formats!");
-        return TranscodingErrorCode::kMalformed;
+        return AMEDIA_ERROR_MALFORMED;
     }
 
     for (int i = 0; i < trackFormats.size(); ++i) {
@@ -341,43 +375,43 @@
         }
         if (err != AMEDIA_OK) {
             ALOGE("failed to configure track format for track %d: %d", i, err);
-            return toTranscodingError(err);
+            return err;
         }
     }
 
     err = mTranscoder->configureDestination(dstFd.get());
     if (err != AMEDIA_OK) {
         ALOGE("failed to configure dest: %d", err);
-        return toTranscodingError(err);
+        return err;
     }
 
-    return TranscodingErrorCode::kNoError;
+    return AMEDIA_OK;
 }
 
-TranscodingErrorCode TranscoderWrapper::handleStart(
+media_status_t TranscoderWrapper::handleStart(
         ClientIdType clientId, JobIdType jobId, const TranscodingRequestParcel& request,
         const std::shared_ptr<ITranscodingClientCallback>& clientCb) {
-    ALOGI("setting up transcoder for start");
-    TranscodingErrorCode err = setupTranscoder(clientId, jobId, request, clientCb);
-    if (err != TranscodingErrorCode::kNoError) {
+    ALOGI("%s: setting up transcoder for start", __FUNCTION__);
+    media_status_t err = setupTranscoder(clientId, jobId, request, clientCb);
+    if (err != AMEDIA_OK) {
         ALOGI("%s: failed to setup transcoder", __FUNCTION__);
         return err;
     }
 
-    media_status_t status = mTranscoder->start();
-    if (status != AMEDIA_OK) {
+    err = mTranscoder->start();
+    if (err != AMEDIA_OK) {
         ALOGE("%s: failed to start transcoder: %d", __FUNCTION__, err);
-        return toTranscodingError(status);
+        return err;
     }
 
     ALOGI("%s: transcoder started", __FUNCTION__);
-    return TranscodingErrorCode::kNoError;
+    return AMEDIA_OK;
 }
 
-TranscodingErrorCode TranscoderWrapper::handlePause(ClientIdType clientId, JobIdType jobId) {
+media_status_t TranscoderWrapper::handlePause(ClientIdType clientId, JobIdType jobId) {
     if (mTranscoder == nullptr) {
         ALOGE("%s: transcoder is not running", __FUNCTION__);
-        return TranscodingErrorCode::kInvalidOperation;
+        return AMEDIA_ERROR_INVALID_OPERATION;
     }
 
     if (clientId != mCurrentClientId || jobId != mCurrentJobId) {
@@ -385,19 +419,21 @@
               (long long)clientId, jobId, (long long)mCurrentClientId, mCurrentJobId);
     }
 
+    ALOGI("%s: pausing transcoder", __FUNCTION__);
+
     std::shared_ptr<const Parcel> pauseStates;
     media_status_t err = mTranscoder->pause(&pauseStates);
     if (err != AMEDIA_OK) {
         ALOGE("%s: failed to pause transcoder: %d", __FUNCTION__, err);
-        return toTranscodingError(err);
+        return err;
     }
     mPausedStateMap[JobKeyType(clientId, jobId)] = pauseStates;
 
     ALOGI("%s: transcoder paused", __FUNCTION__);
-    return TranscodingErrorCode::kNoError;
+    return AMEDIA_OK;
 }
 
-TranscodingErrorCode TranscoderWrapper::handleResume(
+media_status_t TranscoderWrapper::handleResume(
         ClientIdType clientId, JobIdType jobId, const TranscodingRequestParcel& request,
         const std::shared_ptr<ITranscodingClientCallback>& clientCb) {
     std::shared_ptr<const Parcel> pausedState;
@@ -407,24 +443,24 @@
         mPausedStateMap.erase(it);
     } else {
         ALOGE("%s: can't find paused state", __FUNCTION__);
-        return TranscodingErrorCode::kInvalidOperation;
+        return AMEDIA_ERROR_INVALID_OPERATION;
     }
 
-    ALOGI("setting up transcoder for resume");
-    TranscodingErrorCode err = setupTranscoder(clientId, jobId, request, clientCb, pausedState);
-    if (err != TranscodingErrorCode::kNoError) {
-        ALOGE("%s: failed to setup transcoder", __FUNCTION__);
+    ALOGI("%s: setting up transcoder for resume", __FUNCTION__);
+    media_status_t err = setupTranscoder(clientId, jobId, request, clientCb, pausedState);
+    if (err != AMEDIA_OK) {
+        ALOGE("%s: failed to setup transcoder: %d", __FUNCTION__, err);
         return err;
     }
 
-    media_status_t status = mTranscoder->resume();
-    if (status != AMEDIA_OK) {
+    err = mTranscoder->resume();
+    if (err != AMEDIA_OK) {
         ALOGE("%s: failed to resume transcoder: %d", __FUNCTION__, err);
-        return toTranscodingError(status);
+        return err;
     }
 
     ALOGI("%s: transcoder resumed", __FUNCTION__);
-    return TranscodingErrorCode::kNoError;
+    return AMEDIA_OK;
 }
 
 void TranscoderWrapper::cleanup() {
@@ -435,12 +471,10 @@
 }
 
 void TranscoderWrapper::queueEvent(Event::Type type, ClientIdType clientId, JobIdType jobId,
-                                   const std::function<void()> runnable) {
-    ALOGV("%s: job {%lld, %d}: %s", __FUNCTION__, (long long)clientId, jobId, toString(type));
-
+                                   const std::function<void()> runnable, int32_t arg) {
     std::scoped_lock lock{mLock};
 
-    mQueue.push_back({type, clientId, jobId, runnable});
+    mQueue.push_back({type, clientId, jobId, runnable, arg});
     mCondition.notify_one();
 }
 
@@ -457,8 +491,7 @@
         Event event = *mQueue.begin();
         mQueue.pop_front();
 
-        ALOGD("%s: job {%lld, %d}: %s", __FUNCTION__, (long long)event.clientId, event.jobId,
-              toString(event.type));
+        ALOGD("%s: %s", __FUNCTION__, toString(event).c_str());
 
         lock.unlock();
         event.runnable();