xref: /aosp_15_r20/frameworks/av/media/module/libmediatranscoding/TranscoderWrapper.cpp (revision ec779b8e0859a360c3d303172224686826e6e0e1)
1*ec779b8eSAndroid Build Coastguard Worker /*
2*ec779b8eSAndroid Build Coastguard Worker  * Copyright (C) 2020 The Android Open Source Project
3*ec779b8eSAndroid Build Coastguard Worker  *
4*ec779b8eSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*ec779b8eSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*ec779b8eSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*ec779b8eSAndroid Build Coastguard Worker  *
8*ec779b8eSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*ec779b8eSAndroid Build Coastguard Worker  *
10*ec779b8eSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*ec779b8eSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*ec779b8eSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*ec779b8eSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*ec779b8eSAndroid Build Coastguard Worker  * limitations under the License.
15*ec779b8eSAndroid Build Coastguard Worker  */
16*ec779b8eSAndroid Build Coastguard Worker 
17*ec779b8eSAndroid Build Coastguard Worker //#define LOG_NDEBUG 0
18*ec779b8eSAndroid Build Coastguard Worker #define LOG_TAG "TranscoderWrapper"
19*ec779b8eSAndroid Build Coastguard Worker 
20*ec779b8eSAndroid Build Coastguard Worker #include <aidl/android/media/TranscodingErrorCode.h>
21*ec779b8eSAndroid Build Coastguard Worker #include <aidl/android/media/TranscodingRequestParcel.h>
22*ec779b8eSAndroid Build Coastguard Worker #include <media/MediaTranscoder.h>
23*ec779b8eSAndroid Build Coastguard Worker #include <media/NdkCommon.h>
24*ec779b8eSAndroid Build Coastguard Worker #include <media/TranscoderWrapper.h>
25*ec779b8eSAndroid Build Coastguard Worker #include <media/TranscodingRequest.h>
26*ec779b8eSAndroid Build Coastguard Worker #include <utils/AndroidThreads.h>
27*ec779b8eSAndroid Build Coastguard Worker #include <utils/Log.h>
28*ec779b8eSAndroid Build Coastguard Worker 
29*ec779b8eSAndroid Build Coastguard Worker #include <thread>
30*ec779b8eSAndroid Build Coastguard Worker 
31*ec779b8eSAndroid Build Coastguard Worker namespace android {
32*ec779b8eSAndroid Build Coastguard Worker using Status = ::ndk::ScopedAStatus;
33*ec779b8eSAndroid Build Coastguard Worker using ::aidl::android::media::TranscodingErrorCode;
34*ec779b8eSAndroid Build Coastguard Worker using ::aidl::android::media::TranscodingVideoCodecType;
35*ec779b8eSAndroid Build Coastguard Worker using ::aidl::android::media::TranscodingVideoTrackFormat;
36*ec779b8eSAndroid Build Coastguard Worker 
toTranscodingError(media_status_t status)37*ec779b8eSAndroid Build Coastguard Worker static TranscodingErrorCode toTranscodingError(media_status_t status) {
38*ec779b8eSAndroid Build Coastguard Worker     switch (status) {
39*ec779b8eSAndroid Build Coastguard Worker     case AMEDIA_OK:
40*ec779b8eSAndroid Build Coastguard Worker         return TranscodingErrorCode::kNoError;
41*ec779b8eSAndroid Build Coastguard Worker     case AMEDIACODEC_ERROR_INSUFFICIENT_RESOURCE:  // FALLTHRU
42*ec779b8eSAndroid Build Coastguard Worker     case AMEDIACODEC_ERROR_RECLAIMED:
43*ec779b8eSAndroid Build Coastguard Worker         return TranscodingErrorCode::kInsufficientResources;
44*ec779b8eSAndroid Build Coastguard Worker     case AMEDIA_ERROR_MALFORMED:
45*ec779b8eSAndroid Build Coastguard Worker         return TranscodingErrorCode::kMalformed;
46*ec779b8eSAndroid Build Coastguard Worker     case AMEDIA_ERROR_UNSUPPORTED:
47*ec779b8eSAndroid Build Coastguard Worker         return TranscodingErrorCode::kUnsupported;
48*ec779b8eSAndroid Build Coastguard Worker     case AMEDIA_ERROR_INVALID_OBJECT:  // FALLTHRU
49*ec779b8eSAndroid Build Coastguard Worker     case AMEDIA_ERROR_INVALID_PARAMETER:
50*ec779b8eSAndroid Build Coastguard Worker         return TranscodingErrorCode::kInvalidParameter;
51*ec779b8eSAndroid Build Coastguard Worker     case AMEDIA_ERROR_INVALID_OPERATION:
52*ec779b8eSAndroid Build Coastguard Worker         return TranscodingErrorCode::kInvalidOperation;
53*ec779b8eSAndroid Build Coastguard Worker     case AMEDIA_ERROR_IO:
54*ec779b8eSAndroid Build Coastguard Worker         return TranscodingErrorCode::kErrorIO;
55*ec779b8eSAndroid Build Coastguard Worker     case AMEDIA_ERROR_UNKNOWN:  // FALLTHRU
56*ec779b8eSAndroid Build Coastguard Worker     default:
57*ec779b8eSAndroid Build Coastguard Worker         return TranscodingErrorCode::kUnknown;
58*ec779b8eSAndroid Build Coastguard Worker     }
59*ec779b8eSAndroid Build Coastguard Worker }
60*ec779b8eSAndroid Build Coastguard Worker 
getVideoFormat(const char * originalMime,const std::optional<TranscodingVideoTrackFormat> & requestedFormat)61*ec779b8eSAndroid Build Coastguard Worker static std::shared_ptr<AMediaFormat> getVideoFormat(
62*ec779b8eSAndroid Build Coastguard Worker         const char* originalMime,
63*ec779b8eSAndroid Build Coastguard Worker         const std::optional<TranscodingVideoTrackFormat>& requestedFormat) {
64*ec779b8eSAndroid Build Coastguard Worker     if (requestedFormat == std::nullopt) {
65*ec779b8eSAndroid Build Coastguard Worker         return nullptr;
66*ec779b8eSAndroid Build Coastguard Worker     }
67*ec779b8eSAndroid Build Coastguard Worker 
68*ec779b8eSAndroid Build Coastguard Worker     std::shared_ptr<AMediaFormat> format =
69*ec779b8eSAndroid Build Coastguard Worker             std::shared_ptr<AMediaFormat>(AMediaFormat_new(), &AMediaFormat_delete);
70*ec779b8eSAndroid Build Coastguard Worker     bool changed = false;
71*ec779b8eSAndroid Build Coastguard Worker     if (requestedFormat->codecType == TranscodingVideoCodecType::kHevc &&
72*ec779b8eSAndroid Build Coastguard Worker         strcmp(originalMime, AMEDIA_MIMETYPE_VIDEO_HEVC)) {
73*ec779b8eSAndroid Build Coastguard Worker         AMediaFormat_setString(format.get(), AMEDIAFORMAT_KEY_MIME, AMEDIA_MIMETYPE_VIDEO_HEVC);
74*ec779b8eSAndroid Build Coastguard Worker         changed = true;
75*ec779b8eSAndroid Build Coastguard Worker     } else if (requestedFormat->codecType == TranscodingVideoCodecType::kAvc &&
76*ec779b8eSAndroid Build Coastguard Worker                strcmp(originalMime, AMEDIA_MIMETYPE_VIDEO_AVC)) {
77*ec779b8eSAndroid Build Coastguard Worker         AMediaFormat_setString(format.get(), AMEDIAFORMAT_KEY_MIME, AMEDIA_MIMETYPE_VIDEO_AVC);
78*ec779b8eSAndroid Build Coastguard Worker         changed = true;
79*ec779b8eSAndroid Build Coastguard Worker     }
80*ec779b8eSAndroid Build Coastguard Worker     if (requestedFormat->bitrateBps > 0) {
81*ec779b8eSAndroid Build Coastguard Worker         AMediaFormat_setInt32(format.get(), AMEDIAFORMAT_KEY_BIT_RATE, requestedFormat->bitrateBps);
82*ec779b8eSAndroid Build Coastguard Worker         changed = true;
83*ec779b8eSAndroid Build Coastguard Worker     }
84*ec779b8eSAndroid Build Coastguard Worker     // TODO: translate other fields from requestedFormat to the format for MediaTranscoder.
85*ec779b8eSAndroid Build Coastguard Worker     // Also need to determine more settings to expose in TranscodingVideoTrackFormat.
86*ec779b8eSAndroid Build Coastguard Worker     if (!changed) {
87*ec779b8eSAndroid Build Coastguard Worker         // Use null format for passthru.
88*ec779b8eSAndroid Build Coastguard Worker         format.reset();
89*ec779b8eSAndroid Build Coastguard Worker     }
90*ec779b8eSAndroid Build Coastguard Worker     return format;
91*ec779b8eSAndroid Build Coastguard Worker }
92*ec779b8eSAndroid Build Coastguard Worker 
93*ec779b8eSAndroid Build Coastguard Worker //static
toString(const Event & event)94*ec779b8eSAndroid Build Coastguard Worker std::string TranscoderWrapper::toString(const Event& event) {
95*ec779b8eSAndroid Build Coastguard Worker     std::string typeStr;
96*ec779b8eSAndroid Build Coastguard Worker     switch (event.type) {
97*ec779b8eSAndroid Build Coastguard Worker     case Event::Start:
98*ec779b8eSAndroid Build Coastguard Worker         typeStr = "Start";
99*ec779b8eSAndroid Build Coastguard Worker         break;
100*ec779b8eSAndroid Build Coastguard Worker     case Event::Pause:
101*ec779b8eSAndroid Build Coastguard Worker         typeStr = "Pause";
102*ec779b8eSAndroid Build Coastguard Worker         break;
103*ec779b8eSAndroid Build Coastguard Worker     case Event::Resume:
104*ec779b8eSAndroid Build Coastguard Worker         typeStr = "Resume";
105*ec779b8eSAndroid Build Coastguard Worker         break;
106*ec779b8eSAndroid Build Coastguard Worker     case Event::Stop:
107*ec779b8eSAndroid Build Coastguard Worker         typeStr = "Stop";
108*ec779b8eSAndroid Build Coastguard Worker         break;
109*ec779b8eSAndroid Build Coastguard Worker     case Event::Finish:
110*ec779b8eSAndroid Build Coastguard Worker         typeStr = "Finish";
111*ec779b8eSAndroid Build Coastguard Worker         break;
112*ec779b8eSAndroid Build Coastguard Worker     case Event::Error:
113*ec779b8eSAndroid Build Coastguard Worker         typeStr = "Error";
114*ec779b8eSAndroid Build Coastguard Worker         break;
115*ec779b8eSAndroid Build Coastguard Worker     case Event::Progress:
116*ec779b8eSAndroid Build Coastguard Worker         typeStr = "Progress";
117*ec779b8eSAndroid Build Coastguard Worker         break;
118*ec779b8eSAndroid Build Coastguard Worker     case Event::HeartBeat:
119*ec779b8eSAndroid Build Coastguard Worker         typeStr = "HeartBeat";
120*ec779b8eSAndroid Build Coastguard Worker         break;
121*ec779b8eSAndroid Build Coastguard Worker     case Event::Abandon:
122*ec779b8eSAndroid Build Coastguard Worker         typeStr = "Abandon";
123*ec779b8eSAndroid Build Coastguard Worker         break;
124*ec779b8eSAndroid Build Coastguard Worker     default:
125*ec779b8eSAndroid Build Coastguard Worker         return "(unknown)";
126*ec779b8eSAndroid Build Coastguard Worker     }
127*ec779b8eSAndroid Build Coastguard Worker     std::string result;
128*ec779b8eSAndroid Build Coastguard Worker     result = "session {" + std::to_string(event.clientId) + "," + std::to_string(event.sessionId) +
129*ec779b8eSAndroid Build Coastguard Worker              "}: " + typeStr;
130*ec779b8eSAndroid Build Coastguard Worker     if (event.type == Event::Error || event.type == Event::Progress) {
131*ec779b8eSAndroid Build Coastguard Worker         result += " " + std::to_string(event.arg);
132*ec779b8eSAndroid Build Coastguard Worker     }
133*ec779b8eSAndroid Build Coastguard Worker     return result;
134*ec779b8eSAndroid Build Coastguard Worker }
135*ec779b8eSAndroid Build Coastguard Worker 
136*ec779b8eSAndroid Build Coastguard Worker class TranscoderWrapper::CallbackImpl : public MediaTranscoder::CallbackInterface {
137*ec779b8eSAndroid Build Coastguard Worker public:
CallbackImpl(const std::shared_ptr<TranscoderWrapper> & owner,ClientIdType clientId,SessionIdType sessionId)138*ec779b8eSAndroid Build Coastguard Worker     CallbackImpl(const std::shared_ptr<TranscoderWrapper>& owner, ClientIdType clientId,
139*ec779b8eSAndroid Build Coastguard Worker                  SessionIdType sessionId)
140*ec779b8eSAndroid Build Coastguard Worker           : mOwner(owner), mClientId(clientId), mSessionId(sessionId) {}
141*ec779b8eSAndroid Build Coastguard Worker 
onFinished(const MediaTranscoder * transcoder __unused)142*ec779b8eSAndroid Build Coastguard Worker     virtual void onFinished(const MediaTranscoder* transcoder __unused) override {
143*ec779b8eSAndroid Build Coastguard Worker         auto owner = mOwner.lock();
144*ec779b8eSAndroid Build Coastguard Worker         if (owner != nullptr) {
145*ec779b8eSAndroid Build Coastguard Worker             owner->onFinish(mClientId, mSessionId);
146*ec779b8eSAndroid Build Coastguard Worker         }
147*ec779b8eSAndroid Build Coastguard Worker     }
148*ec779b8eSAndroid Build Coastguard Worker 
onError(const MediaTranscoder * transcoder __unused,media_status_t error)149*ec779b8eSAndroid Build Coastguard Worker     virtual void onError(const MediaTranscoder* transcoder __unused,
150*ec779b8eSAndroid Build Coastguard Worker                          media_status_t error) override {
151*ec779b8eSAndroid Build Coastguard Worker         auto owner = mOwner.lock();
152*ec779b8eSAndroid Build Coastguard Worker         if (owner != nullptr) {
153*ec779b8eSAndroid Build Coastguard Worker             owner->onError(mClientId, mSessionId, error);
154*ec779b8eSAndroid Build Coastguard Worker         }
155*ec779b8eSAndroid Build Coastguard Worker     }
156*ec779b8eSAndroid Build Coastguard Worker 
onProgressUpdate(const MediaTranscoder * transcoder __unused,int32_t progress)157*ec779b8eSAndroid Build Coastguard Worker     virtual void onProgressUpdate(const MediaTranscoder* transcoder __unused,
158*ec779b8eSAndroid Build Coastguard Worker                                   int32_t progress) override {
159*ec779b8eSAndroid Build Coastguard Worker         auto owner = mOwner.lock();
160*ec779b8eSAndroid Build Coastguard Worker         if (owner != nullptr) {
161*ec779b8eSAndroid Build Coastguard Worker             owner->onProgress(mClientId, mSessionId, progress);
162*ec779b8eSAndroid Build Coastguard Worker         }
163*ec779b8eSAndroid Build Coastguard Worker     }
164*ec779b8eSAndroid Build Coastguard Worker 
onHeartBeat(const MediaTranscoder * transcoder __unused)165*ec779b8eSAndroid Build Coastguard Worker     virtual void onHeartBeat(const MediaTranscoder* transcoder __unused) override {
166*ec779b8eSAndroid Build Coastguard Worker         auto owner = mOwner.lock();
167*ec779b8eSAndroid Build Coastguard Worker         if (owner != nullptr) {
168*ec779b8eSAndroid Build Coastguard Worker             owner->onHeartBeat(mClientId, mSessionId);
169*ec779b8eSAndroid Build Coastguard Worker         }
170*ec779b8eSAndroid Build Coastguard Worker     }
171*ec779b8eSAndroid Build Coastguard Worker 
onCodecResourceLost(const MediaTranscoder * transcoder __unused,const std::shared_ptr<ndk::ScopedAParcel> & pausedState __unused)172*ec779b8eSAndroid Build Coastguard Worker     virtual void onCodecResourceLost(const MediaTranscoder* transcoder __unused,
173*ec779b8eSAndroid Build Coastguard Worker                                      const std::shared_ptr<ndk::ScopedAParcel>& pausedState
174*ec779b8eSAndroid Build Coastguard Worker                                              __unused) override {
175*ec779b8eSAndroid Build Coastguard Worker         ALOGV("%s: session {%lld, %d}", __FUNCTION__, (long long)mClientId, mSessionId);
176*ec779b8eSAndroid Build Coastguard Worker     }
177*ec779b8eSAndroid Build Coastguard Worker 
178*ec779b8eSAndroid Build Coastguard Worker private:
179*ec779b8eSAndroid Build Coastguard Worker     std::weak_ptr<TranscoderWrapper> mOwner;
180*ec779b8eSAndroid Build Coastguard Worker     ClientIdType mClientId;
181*ec779b8eSAndroid Build Coastguard Worker     SessionIdType mSessionId;
182*ec779b8eSAndroid Build Coastguard Worker };
183*ec779b8eSAndroid Build Coastguard Worker 
TranscoderWrapper(const std::shared_ptr<TranscoderCallbackInterface> & cb,const std::shared_ptr<TranscodingLogger> & logger,int64_t heartBeatIntervalUs)184*ec779b8eSAndroid Build Coastguard Worker TranscoderWrapper::TranscoderWrapper(const std::shared_ptr<TranscoderCallbackInterface>& cb,
185*ec779b8eSAndroid Build Coastguard Worker                                      const std::shared_ptr<TranscodingLogger>& logger,
186*ec779b8eSAndroid Build Coastguard Worker                                      int64_t heartBeatIntervalUs)
187*ec779b8eSAndroid Build Coastguard Worker       : mCallback(cb),
188*ec779b8eSAndroid Build Coastguard Worker         mLogger(logger),
189*ec779b8eSAndroid Build Coastguard Worker         mHeartBeatIntervalUs(heartBeatIntervalUs),
190*ec779b8eSAndroid Build Coastguard Worker         mCurrentClientId(0),
191*ec779b8eSAndroid Build Coastguard Worker         mCurrentSessionId(-1),
192*ec779b8eSAndroid Build Coastguard Worker         mLooperReady(false) {
193*ec779b8eSAndroid Build Coastguard Worker     ALOGV("TranscoderWrapper CTOR: %p", this);
194*ec779b8eSAndroid Build Coastguard Worker }
195*ec779b8eSAndroid Build Coastguard Worker 
~TranscoderWrapper()196*ec779b8eSAndroid Build Coastguard Worker TranscoderWrapper::~TranscoderWrapper() {
197*ec779b8eSAndroid Build Coastguard Worker     ALOGV("TranscoderWrapper DTOR: %p", this);
198*ec779b8eSAndroid Build Coastguard Worker }
199*ec779b8eSAndroid Build Coastguard Worker 
isResourceError(media_status_t err)200*ec779b8eSAndroid Build Coastguard Worker static bool isResourceError(media_status_t err) {
201*ec779b8eSAndroid Build Coastguard Worker     return err == AMEDIACODEC_ERROR_RECLAIMED || err == AMEDIACODEC_ERROR_INSUFFICIENT_RESOURCE;
202*ec779b8eSAndroid Build Coastguard Worker }
203*ec779b8eSAndroid Build Coastguard Worker 
reportError(ClientIdType clientId,SessionIdType sessionId,media_status_t err)204*ec779b8eSAndroid Build Coastguard Worker void TranscoderWrapper::reportError(ClientIdType clientId, SessionIdType sessionId,
205*ec779b8eSAndroid Build Coastguard Worker                                     media_status_t err) {
206*ec779b8eSAndroid Build Coastguard Worker     auto callback = mCallback.lock();
207*ec779b8eSAndroid Build Coastguard Worker     if (callback != nullptr) {
208*ec779b8eSAndroid Build Coastguard Worker         if (isResourceError(err)) {
209*ec779b8eSAndroid Build Coastguard Worker             // Add a placeholder pause state to mPausedStateMap. This is required when resuming.
210*ec779b8eSAndroid Build Coastguard Worker             // TODO: remove this when transcoder pause/resume logic is ready. New logic will
211*ec779b8eSAndroid Build Coastguard Worker             // no longer use the pause states.
212*ec779b8eSAndroid Build Coastguard Worker             auto it = mPausedStateMap.find(SessionKeyType(clientId, sessionId));
213*ec779b8eSAndroid Build Coastguard Worker             if (it == mPausedStateMap.end()) {
214*ec779b8eSAndroid Build Coastguard Worker                 mPausedStateMap.emplace(SessionKeyType(clientId, sessionId),
215*ec779b8eSAndroid Build Coastguard Worker                                         new ndk::ScopedAParcel());
216*ec779b8eSAndroid Build Coastguard Worker             }
217*ec779b8eSAndroid Build Coastguard Worker 
218*ec779b8eSAndroid Build Coastguard Worker             callback->onResourceLost(clientId, sessionId);
219*ec779b8eSAndroid Build Coastguard Worker         } else {
220*ec779b8eSAndroid Build Coastguard Worker             callback->onError(clientId, sessionId, toTranscodingError(err));
221*ec779b8eSAndroid Build Coastguard Worker         }
222*ec779b8eSAndroid Build Coastguard Worker     }
223*ec779b8eSAndroid Build Coastguard Worker }
224*ec779b8eSAndroid Build Coastguard Worker 
start(ClientIdType clientId,SessionIdType sessionId,const TranscodingRequestParcel & requestParcel,uid_t callingUid,const std::shared_ptr<ITranscodingClientCallback> & clientCb)225*ec779b8eSAndroid Build Coastguard Worker void TranscoderWrapper::start(ClientIdType clientId, SessionIdType sessionId,
226*ec779b8eSAndroid Build Coastguard Worker                               const TranscodingRequestParcel& requestParcel, uid_t callingUid,
227*ec779b8eSAndroid Build Coastguard Worker                               const std::shared_ptr<ITranscodingClientCallback>& clientCb) {
228*ec779b8eSAndroid Build Coastguard Worker     TranscodingRequest request{requestParcel};
229*ec779b8eSAndroid Build Coastguard Worker     queueEvent(Event::Start, clientId, sessionId, [=] {
230*ec779b8eSAndroid Build Coastguard Worker         media_status_t err = handleStart(clientId, sessionId, request, callingUid, clientCb);
231*ec779b8eSAndroid Build Coastguard Worker         if (err != AMEDIA_OK) {
232*ec779b8eSAndroid Build Coastguard Worker             cleanup();
233*ec779b8eSAndroid Build Coastguard Worker             reportError(clientId, sessionId, err);
234*ec779b8eSAndroid Build Coastguard Worker         } else {
235*ec779b8eSAndroid Build Coastguard Worker             auto callback = mCallback.lock();
236*ec779b8eSAndroid Build Coastguard Worker             if (callback != nullptr) {
237*ec779b8eSAndroid Build Coastguard Worker                 callback->onStarted(clientId, sessionId);
238*ec779b8eSAndroid Build Coastguard Worker             }
239*ec779b8eSAndroid Build Coastguard Worker         }
240*ec779b8eSAndroid Build Coastguard Worker     });
241*ec779b8eSAndroid Build Coastguard Worker }
242*ec779b8eSAndroid Build Coastguard Worker 
pause(ClientIdType clientId,SessionIdType sessionId)243*ec779b8eSAndroid Build Coastguard Worker void TranscoderWrapper::pause(ClientIdType clientId, SessionIdType sessionId) {
244*ec779b8eSAndroid Build Coastguard Worker     queueEvent(Event::Pause, clientId, sessionId, [=] {
245*ec779b8eSAndroid Build Coastguard Worker         media_status_t err = handlePause(clientId, sessionId);
246*ec779b8eSAndroid Build Coastguard Worker 
247*ec779b8eSAndroid Build Coastguard Worker         cleanup();
248*ec779b8eSAndroid Build Coastguard Worker 
249*ec779b8eSAndroid Build Coastguard Worker         if (err != AMEDIA_OK) {
250*ec779b8eSAndroid Build Coastguard Worker             reportError(clientId, sessionId, err);
251*ec779b8eSAndroid Build Coastguard Worker         } else {
252*ec779b8eSAndroid Build Coastguard Worker             auto callback = mCallback.lock();
253*ec779b8eSAndroid Build Coastguard Worker             if (callback != nullptr) {
254*ec779b8eSAndroid Build Coastguard Worker                 callback->onPaused(clientId, sessionId);
255*ec779b8eSAndroid Build Coastguard Worker             }
256*ec779b8eSAndroid Build Coastguard Worker         }
257*ec779b8eSAndroid Build Coastguard Worker     });
258*ec779b8eSAndroid Build Coastguard Worker }
259*ec779b8eSAndroid Build Coastguard Worker 
resume(ClientIdType clientId,SessionIdType sessionId,const TranscodingRequestParcel & requestParcel,uid_t callingUid,const std::shared_ptr<ITranscodingClientCallback> & clientCb)260*ec779b8eSAndroid Build Coastguard Worker void TranscoderWrapper::resume(ClientIdType clientId, SessionIdType sessionId,
261*ec779b8eSAndroid Build Coastguard Worker                                const TranscodingRequestParcel& requestParcel, uid_t callingUid,
262*ec779b8eSAndroid Build Coastguard Worker                                const std::shared_ptr<ITranscodingClientCallback>& clientCb) {
263*ec779b8eSAndroid Build Coastguard Worker     TranscodingRequest request{requestParcel};
264*ec779b8eSAndroid Build Coastguard Worker     queueEvent(Event::Resume, clientId, sessionId, [=] {
265*ec779b8eSAndroid Build Coastguard Worker         media_status_t err = handleResume(clientId, sessionId, request, callingUid, clientCb);
266*ec779b8eSAndroid Build Coastguard Worker         if (err != AMEDIA_OK) {
267*ec779b8eSAndroid Build Coastguard Worker             cleanup();
268*ec779b8eSAndroid Build Coastguard Worker             reportError(clientId, sessionId, err);
269*ec779b8eSAndroid Build Coastguard Worker         } else {
270*ec779b8eSAndroid Build Coastguard Worker             auto callback = mCallback.lock();
271*ec779b8eSAndroid Build Coastguard Worker             if (callback != nullptr) {
272*ec779b8eSAndroid Build Coastguard Worker                 callback->onResumed(clientId, sessionId);
273*ec779b8eSAndroid Build Coastguard Worker             }
274*ec779b8eSAndroid Build Coastguard Worker         }
275*ec779b8eSAndroid Build Coastguard Worker     });
276*ec779b8eSAndroid Build Coastguard Worker }
277*ec779b8eSAndroid Build Coastguard Worker 
stop(ClientIdType clientId,SessionIdType sessionId,bool abandon)278*ec779b8eSAndroid Build Coastguard Worker void TranscoderWrapper::stop(ClientIdType clientId, SessionIdType sessionId, bool abandon) {
279*ec779b8eSAndroid Build Coastguard Worker     queueEvent(Event::Stop, clientId, sessionId, [=] {
280*ec779b8eSAndroid Build Coastguard Worker         if (mTranscoder != nullptr && clientId == mCurrentClientId &&
281*ec779b8eSAndroid Build Coastguard Worker             sessionId == mCurrentSessionId) {
282*ec779b8eSAndroid Build Coastguard Worker             // Cancelling the currently running session.
283*ec779b8eSAndroid Build Coastguard Worker             media_status_t err = mTranscoder->cancel();
284*ec779b8eSAndroid Build Coastguard Worker             if (err != AMEDIA_OK) {
285*ec779b8eSAndroid Build Coastguard Worker                 ALOGW("failed to stop transcoder: %d", err);
286*ec779b8eSAndroid Build Coastguard Worker             } else {
287*ec779b8eSAndroid Build Coastguard Worker                 ALOGI("transcoder stopped");
288*ec779b8eSAndroid Build Coastguard Worker             }
289*ec779b8eSAndroid Build Coastguard Worker             logSessionEnded(TranscodingLogger::SessionEndedReason::CANCELLED, err);
290*ec779b8eSAndroid Build Coastguard Worker             cleanup();
291*ec779b8eSAndroid Build Coastguard Worker         } else {
292*ec779b8eSAndroid Build Coastguard Worker             // For sessions that's not currently running, release any pausedState for the session.
293*ec779b8eSAndroid Build Coastguard Worker             mPausedStateMap.erase(SessionKeyType(clientId, sessionId));
294*ec779b8eSAndroid Build Coastguard Worker         }
295*ec779b8eSAndroid Build Coastguard Worker         // No callback needed for stop.
296*ec779b8eSAndroid Build Coastguard Worker     });
297*ec779b8eSAndroid Build Coastguard Worker 
298*ec779b8eSAndroid Build Coastguard Worker     if (abandon) {
299*ec779b8eSAndroid Build Coastguard Worker         queueEvent(Event::Abandon, 0, 0, nullptr);
300*ec779b8eSAndroid Build Coastguard Worker     }
301*ec779b8eSAndroid Build Coastguard Worker }
302*ec779b8eSAndroid Build Coastguard Worker 
onFinish(ClientIdType clientId,SessionIdType sessionId)303*ec779b8eSAndroid Build Coastguard Worker void TranscoderWrapper::onFinish(ClientIdType clientId, SessionIdType sessionId) {
304*ec779b8eSAndroid Build Coastguard Worker     queueEvent(Event::Finish, clientId, sessionId, [=] {
305*ec779b8eSAndroid Build Coastguard Worker         if (mTranscoder != nullptr && clientId == mCurrentClientId &&
306*ec779b8eSAndroid Build Coastguard Worker             sessionId == mCurrentSessionId) {
307*ec779b8eSAndroid Build Coastguard Worker             logSessionEnded(TranscodingLogger::SessionEndedReason::FINISHED, AMEDIA_OK);
308*ec779b8eSAndroid Build Coastguard Worker             cleanup();
309*ec779b8eSAndroid Build Coastguard Worker         }
310*ec779b8eSAndroid Build Coastguard Worker 
311*ec779b8eSAndroid Build Coastguard Worker         auto callback = mCallback.lock();
312*ec779b8eSAndroid Build Coastguard Worker         if (callback != nullptr) {
313*ec779b8eSAndroid Build Coastguard Worker             callback->onFinish(clientId, sessionId);
314*ec779b8eSAndroid Build Coastguard Worker         }
315*ec779b8eSAndroid Build Coastguard Worker     });
316*ec779b8eSAndroid Build Coastguard Worker }
317*ec779b8eSAndroid Build Coastguard Worker 
onError(ClientIdType clientId,SessionIdType sessionId,media_status_t error)318*ec779b8eSAndroid Build Coastguard Worker void TranscoderWrapper::onError(ClientIdType clientId, SessionIdType sessionId,
319*ec779b8eSAndroid Build Coastguard Worker                                 media_status_t error) {
320*ec779b8eSAndroid Build Coastguard Worker     queueEvent(
321*ec779b8eSAndroid Build Coastguard Worker             Event::Error, clientId, sessionId,
322*ec779b8eSAndroid Build Coastguard Worker             [=] {
323*ec779b8eSAndroid Build Coastguard Worker                 if (mTranscoder != nullptr && clientId == mCurrentClientId &&
324*ec779b8eSAndroid Build Coastguard Worker                     sessionId == mCurrentSessionId) {
325*ec779b8eSAndroid Build Coastguard Worker                     logSessionEnded(TranscodingLogger::SessionEndedReason::ERROR, error);
326*ec779b8eSAndroid Build Coastguard Worker                     cleanup();
327*ec779b8eSAndroid Build Coastguard Worker                 }
328*ec779b8eSAndroid Build Coastguard Worker                 reportError(clientId, sessionId, error);
329*ec779b8eSAndroid Build Coastguard Worker             },
330*ec779b8eSAndroid Build Coastguard Worker             error);
331*ec779b8eSAndroid Build Coastguard Worker }
332*ec779b8eSAndroid Build Coastguard Worker 
onProgress(ClientIdType clientId,SessionIdType sessionId,int32_t progress)333*ec779b8eSAndroid Build Coastguard Worker void TranscoderWrapper::onProgress(ClientIdType clientId, SessionIdType sessionId,
334*ec779b8eSAndroid Build Coastguard Worker                                    int32_t progress) {
335*ec779b8eSAndroid Build Coastguard Worker     queueEvent(
336*ec779b8eSAndroid Build Coastguard Worker             Event::Progress, clientId, sessionId,
337*ec779b8eSAndroid Build Coastguard Worker             [=] {
338*ec779b8eSAndroid Build Coastguard Worker                 auto callback = mCallback.lock();
339*ec779b8eSAndroid Build Coastguard Worker                 if (callback != nullptr) {
340*ec779b8eSAndroid Build Coastguard Worker                     callback->onProgressUpdate(clientId, sessionId, progress);
341*ec779b8eSAndroid Build Coastguard Worker                 }
342*ec779b8eSAndroid Build Coastguard Worker             },
343*ec779b8eSAndroid Build Coastguard Worker             progress);
344*ec779b8eSAndroid Build Coastguard Worker }
345*ec779b8eSAndroid Build Coastguard Worker 
onHeartBeat(ClientIdType clientId,SessionIdType sessionId)346*ec779b8eSAndroid Build Coastguard Worker void TranscoderWrapper::onHeartBeat(ClientIdType clientId, SessionIdType sessionId) {
347*ec779b8eSAndroid Build Coastguard Worker     queueEvent(Event::HeartBeat, clientId, sessionId, [=] {
348*ec779b8eSAndroid Build Coastguard Worker         auto callback = mCallback.lock();
349*ec779b8eSAndroid Build Coastguard Worker         if (callback != nullptr) {
350*ec779b8eSAndroid Build Coastguard Worker             callback->onHeartBeat(clientId, sessionId);
351*ec779b8eSAndroid Build Coastguard Worker         }
352*ec779b8eSAndroid Build Coastguard Worker     });
353*ec779b8eSAndroid Build Coastguard Worker }
354*ec779b8eSAndroid Build Coastguard Worker 
setupTranscoder(ClientIdType clientId,SessionIdType sessionId,const TranscodingRequestParcel & request,uid_t callingUid,const std::shared_ptr<ITranscodingClientCallback> & clientCb,TranscodingLogger::SessionEndedReason * failureReason,const std::shared_ptr<ndk::ScopedAParcel> & pausedState)355*ec779b8eSAndroid Build Coastguard Worker media_status_t TranscoderWrapper::setupTranscoder(
356*ec779b8eSAndroid Build Coastguard Worker         ClientIdType clientId, SessionIdType sessionId, const TranscodingRequestParcel& request,
357*ec779b8eSAndroid Build Coastguard Worker         uid_t callingUid, const std::shared_ptr<ITranscodingClientCallback>& clientCb,
358*ec779b8eSAndroid Build Coastguard Worker         TranscodingLogger::SessionEndedReason* failureReason,
359*ec779b8eSAndroid Build Coastguard Worker         const std::shared_ptr<ndk::ScopedAParcel>& pausedState) {
360*ec779b8eSAndroid Build Coastguard Worker     if (clientCb == nullptr) {
361*ec779b8eSAndroid Build Coastguard Worker         ALOGE("client callback is null");
362*ec779b8eSAndroid Build Coastguard Worker         return AMEDIA_ERROR_INVALID_PARAMETER;
363*ec779b8eSAndroid Build Coastguard Worker     }
364*ec779b8eSAndroid Build Coastguard Worker 
365*ec779b8eSAndroid Build Coastguard Worker     if (mTranscoder != nullptr) {
366*ec779b8eSAndroid Build Coastguard Worker         ALOGE("transcoder already running");
367*ec779b8eSAndroid Build Coastguard Worker         return AMEDIA_ERROR_INVALID_OPERATION;
368*ec779b8eSAndroid Build Coastguard Worker     }
369*ec779b8eSAndroid Build Coastguard Worker 
370*ec779b8eSAndroid Build Coastguard Worker     // Unwrap the callback and send heartbeats to the client after each operation during setup.
371*ec779b8eSAndroid Build Coastguard Worker     auto callback = mCallback.lock();
372*ec779b8eSAndroid Build Coastguard Worker     if (callback == nullptr) {
373*ec779b8eSAndroid Build Coastguard Worker         return AMEDIA_ERROR_INVALID_OPERATION;
374*ec779b8eSAndroid Build Coastguard Worker     }
375*ec779b8eSAndroid Build Coastguard Worker 
376*ec779b8eSAndroid Build Coastguard Worker     Status status;
377*ec779b8eSAndroid Build Coastguard Worker     ::ndk::ScopedFileDescriptor srcFd, dstFd;
378*ec779b8eSAndroid Build Coastguard Worker     int srcFdInt = request.sourceFd.get();
379*ec779b8eSAndroid Build Coastguard Worker     if (srcFdInt < 0) {
380*ec779b8eSAndroid Build Coastguard Worker         status = clientCb->openFileDescriptor(request.sourceFilePath, "r", &srcFd);
381*ec779b8eSAndroid Build Coastguard Worker         if (!status.isOk() || srcFd.get() < 0) {
382*ec779b8eSAndroid Build Coastguard Worker             ALOGE("failed to open source");
383*ec779b8eSAndroid Build Coastguard Worker             *failureReason = TranscodingLogger::SessionEndedReason::OPEN_SRC_FD_FAILED;
384*ec779b8eSAndroid Build Coastguard Worker             return AMEDIA_ERROR_IO;
385*ec779b8eSAndroid Build Coastguard Worker         }
386*ec779b8eSAndroid Build Coastguard Worker         srcFdInt = srcFd.get();
387*ec779b8eSAndroid Build Coastguard Worker     }
388*ec779b8eSAndroid Build Coastguard Worker 
389*ec779b8eSAndroid Build Coastguard Worker     callback->onHeartBeat(clientId, sessionId);
390*ec779b8eSAndroid Build Coastguard Worker 
391*ec779b8eSAndroid Build Coastguard Worker     int dstFdInt = request.destinationFd.get();
392*ec779b8eSAndroid Build Coastguard Worker     if (dstFdInt < 0) {
393*ec779b8eSAndroid Build Coastguard Worker         // Open dest file with "rw", as the transcoder could potentially reuse part of it
394*ec779b8eSAndroid Build Coastguard Worker         // for resume case. We might want the further differentiate and open with "w" only
395*ec779b8eSAndroid Build Coastguard Worker         // for start.
396*ec779b8eSAndroid Build Coastguard Worker         status = clientCb->openFileDescriptor(request.destinationFilePath, "rw", &dstFd);
397*ec779b8eSAndroid Build Coastguard Worker         if (!status.isOk() || dstFd.get() < 0) {
398*ec779b8eSAndroid Build Coastguard Worker             ALOGE("failed to open destination");
399*ec779b8eSAndroid Build Coastguard Worker             *failureReason = TranscodingLogger::SessionEndedReason::OPEN_DST_FD_FAILED;
400*ec779b8eSAndroid Build Coastguard Worker             return AMEDIA_ERROR_IO;
401*ec779b8eSAndroid Build Coastguard Worker         }
402*ec779b8eSAndroid Build Coastguard Worker         dstFdInt = dstFd.get();
403*ec779b8eSAndroid Build Coastguard Worker     }
404*ec779b8eSAndroid Build Coastguard Worker 
405*ec779b8eSAndroid Build Coastguard Worker     callback->onHeartBeat(clientId, sessionId);
406*ec779b8eSAndroid Build Coastguard Worker 
407*ec779b8eSAndroid Build Coastguard Worker     mCurrentClientId = clientId;
408*ec779b8eSAndroid Build Coastguard Worker     mCurrentSessionId = sessionId;
409*ec779b8eSAndroid Build Coastguard Worker     mCurrentCallingUid = callingUid;
410*ec779b8eSAndroid Build Coastguard Worker     mTranscoderCb = std::make_shared<CallbackImpl>(shared_from_this(), clientId, sessionId);
411*ec779b8eSAndroid Build Coastguard Worker     mTranscoder = MediaTranscoder::create(mTranscoderCb, mHeartBeatIntervalUs, request.clientPid,
412*ec779b8eSAndroid Build Coastguard Worker                                           request.clientUid, pausedState);
413*ec779b8eSAndroid Build Coastguard Worker     if (mTranscoder == nullptr) {
414*ec779b8eSAndroid Build Coastguard Worker         ALOGE("failed to create transcoder");
415*ec779b8eSAndroid Build Coastguard Worker         *failureReason = TranscodingLogger::SessionEndedReason::CREATE_FAILED;
416*ec779b8eSAndroid Build Coastguard Worker         return AMEDIA_ERROR_UNKNOWN;
417*ec779b8eSAndroid Build Coastguard Worker     }
418*ec779b8eSAndroid Build Coastguard Worker 
419*ec779b8eSAndroid Build Coastguard Worker     callback->onHeartBeat(clientId, sessionId);
420*ec779b8eSAndroid Build Coastguard Worker 
421*ec779b8eSAndroid Build Coastguard Worker     media_status_t err = mTranscoder->configureSource(srcFdInt);
422*ec779b8eSAndroid Build Coastguard Worker     if (err != AMEDIA_OK) {
423*ec779b8eSAndroid Build Coastguard Worker         ALOGE("failed to configure source: %d", err);
424*ec779b8eSAndroid Build Coastguard Worker         *failureReason = TranscodingLogger::SessionEndedReason::CONFIG_SRC_FAILED;
425*ec779b8eSAndroid Build Coastguard Worker         return err;
426*ec779b8eSAndroid Build Coastguard Worker     }
427*ec779b8eSAndroid Build Coastguard Worker 
428*ec779b8eSAndroid Build Coastguard Worker     callback->onHeartBeat(clientId, sessionId);
429*ec779b8eSAndroid Build Coastguard Worker 
430*ec779b8eSAndroid Build Coastguard Worker     std::vector<std::shared_ptr<AMediaFormat>> trackFormats = mTranscoder->getTrackFormats();
431*ec779b8eSAndroid Build Coastguard Worker     if (trackFormats.size() == 0) {
432*ec779b8eSAndroid Build Coastguard Worker         ALOGE("failed to get track formats!");
433*ec779b8eSAndroid Build Coastguard Worker         *failureReason = TranscodingLogger::SessionEndedReason::NO_TRACKS;
434*ec779b8eSAndroid Build Coastguard Worker         return AMEDIA_ERROR_MALFORMED;
435*ec779b8eSAndroid Build Coastguard Worker     }
436*ec779b8eSAndroid Build Coastguard Worker 
437*ec779b8eSAndroid Build Coastguard Worker     callback->onHeartBeat(clientId, sessionId);
438*ec779b8eSAndroid Build Coastguard Worker 
439*ec779b8eSAndroid Build Coastguard Worker     for (int i = 0; i < trackFormats.size(); ++i) {
440*ec779b8eSAndroid Build Coastguard Worker         std::shared_ptr<AMediaFormat> format;
441*ec779b8eSAndroid Build Coastguard Worker         const char* mime = nullptr;
442*ec779b8eSAndroid Build Coastguard Worker         AMediaFormat_getString(trackFormats[i].get(), AMEDIAFORMAT_KEY_MIME, &mime);
443*ec779b8eSAndroid Build Coastguard Worker 
444*ec779b8eSAndroid Build Coastguard Worker         if (!strncmp(mime, "video/", 6)) {
445*ec779b8eSAndroid Build Coastguard Worker             format = getVideoFormat(mime, request.requestedVideoTrackFormat);
446*ec779b8eSAndroid Build Coastguard Worker 
447*ec779b8eSAndroid Build Coastguard Worker             mSrcFormat = trackFormats[i];
448*ec779b8eSAndroid Build Coastguard Worker             mDstFormat = format;
449*ec779b8eSAndroid Build Coastguard Worker         }
450*ec779b8eSAndroid Build Coastguard Worker 
451*ec779b8eSAndroid Build Coastguard Worker         err = mTranscoder->configureTrackFormat(i, format.get());
452*ec779b8eSAndroid Build Coastguard Worker         if (err != AMEDIA_OK) {
453*ec779b8eSAndroid Build Coastguard Worker             ALOGE("failed to configure track format for track %d: %d", i, err);
454*ec779b8eSAndroid Build Coastguard Worker             *failureReason = TranscodingLogger::SessionEndedReason::CONFIG_TRACK_FAILED;
455*ec779b8eSAndroid Build Coastguard Worker             return err;
456*ec779b8eSAndroid Build Coastguard Worker         }
457*ec779b8eSAndroid Build Coastguard Worker 
458*ec779b8eSAndroid Build Coastguard Worker         callback->onHeartBeat(clientId, sessionId);
459*ec779b8eSAndroid Build Coastguard Worker     }
460*ec779b8eSAndroid Build Coastguard Worker 
461*ec779b8eSAndroid Build Coastguard Worker     err = mTranscoder->configureDestination(dstFdInt);
462*ec779b8eSAndroid Build Coastguard Worker     if (err != AMEDIA_OK) {
463*ec779b8eSAndroid Build Coastguard Worker         ALOGE("failed to configure dest: %d", err);
464*ec779b8eSAndroid Build Coastguard Worker         *failureReason = TranscodingLogger::SessionEndedReason::CONFIG_DST_FAILED;
465*ec779b8eSAndroid Build Coastguard Worker         return err;
466*ec779b8eSAndroid Build Coastguard Worker     }
467*ec779b8eSAndroid Build Coastguard Worker 
468*ec779b8eSAndroid Build Coastguard Worker     callback->onHeartBeat(clientId, sessionId);
469*ec779b8eSAndroid Build Coastguard Worker 
470*ec779b8eSAndroid Build Coastguard Worker     return AMEDIA_OK;
471*ec779b8eSAndroid Build Coastguard Worker }
472*ec779b8eSAndroid Build Coastguard Worker 
handleStart(ClientIdType clientId,SessionIdType sessionId,const TranscodingRequestParcel & request,uid_t callingUid,const std::shared_ptr<ITranscodingClientCallback> & clientCb)473*ec779b8eSAndroid Build Coastguard Worker media_status_t TranscoderWrapper::handleStart(
474*ec779b8eSAndroid Build Coastguard Worker         ClientIdType clientId, SessionIdType sessionId, const TranscodingRequestParcel& request,
475*ec779b8eSAndroid Build Coastguard Worker         uid_t callingUid, const std::shared_ptr<ITranscodingClientCallback>& clientCb) {
476*ec779b8eSAndroid Build Coastguard Worker     ALOGI("%s: setting up transcoder for start", __FUNCTION__);
477*ec779b8eSAndroid Build Coastguard Worker     TranscodingLogger::SessionEndedReason reason = TranscodingLogger::SessionEndedReason::UNKNOWN;
478*ec779b8eSAndroid Build Coastguard Worker     media_status_t err =
479*ec779b8eSAndroid Build Coastguard Worker             setupTranscoder(clientId, sessionId, request, callingUid, clientCb, &reason);
480*ec779b8eSAndroid Build Coastguard Worker     if (err != AMEDIA_OK) {
481*ec779b8eSAndroid Build Coastguard Worker         ALOGE("%s: failed to setup transcoder", __FUNCTION__);
482*ec779b8eSAndroid Build Coastguard Worker         logSessionEnded(reason, err);
483*ec779b8eSAndroid Build Coastguard Worker         return err;
484*ec779b8eSAndroid Build Coastguard Worker     }
485*ec779b8eSAndroid Build Coastguard Worker 
486*ec779b8eSAndroid Build Coastguard Worker     mTranscodeStartTime = std::chrono::steady_clock::now();
487*ec779b8eSAndroid Build Coastguard Worker 
488*ec779b8eSAndroid Build Coastguard Worker     err = mTranscoder->start();
489*ec779b8eSAndroid Build Coastguard Worker     if (err != AMEDIA_OK) {
490*ec779b8eSAndroid Build Coastguard Worker         ALOGE("%s: failed to start transcoder: %d", __FUNCTION__, err);
491*ec779b8eSAndroid Build Coastguard Worker         logSessionEnded(TranscodingLogger::SessionEndedReason::START_FAILED, err);
492*ec779b8eSAndroid Build Coastguard Worker         return err;
493*ec779b8eSAndroid Build Coastguard Worker     }
494*ec779b8eSAndroid Build Coastguard Worker 
495*ec779b8eSAndroid Build Coastguard Worker     ALOGI("%s: transcoder started", __FUNCTION__);
496*ec779b8eSAndroid Build Coastguard Worker     return AMEDIA_OK;
497*ec779b8eSAndroid Build Coastguard Worker }
498*ec779b8eSAndroid Build Coastguard Worker 
handlePause(ClientIdType clientId,SessionIdType sessionId)499*ec779b8eSAndroid Build Coastguard Worker media_status_t TranscoderWrapper::handlePause(ClientIdType clientId, SessionIdType sessionId) {
500*ec779b8eSAndroid Build Coastguard Worker     if (mTranscoder == nullptr) {
501*ec779b8eSAndroid Build Coastguard Worker         ALOGE("%s: transcoder is not running", __FUNCTION__);
502*ec779b8eSAndroid Build Coastguard Worker         return AMEDIA_ERROR_INVALID_OPERATION;
503*ec779b8eSAndroid Build Coastguard Worker     }
504*ec779b8eSAndroid Build Coastguard Worker 
505*ec779b8eSAndroid Build Coastguard Worker     if (clientId != mCurrentClientId || sessionId != mCurrentSessionId) {
506*ec779b8eSAndroid Build Coastguard Worker         ALOGW("%s: stopping session {%lld, %d} that's not current session {%lld, %d}", __FUNCTION__,
507*ec779b8eSAndroid Build Coastguard Worker               (long long)clientId, sessionId, (long long)mCurrentClientId, mCurrentSessionId);
508*ec779b8eSAndroid Build Coastguard Worker     }
509*ec779b8eSAndroid Build Coastguard Worker 
510*ec779b8eSAndroid Build Coastguard Worker     ALOGI("%s: pausing transcoder", __FUNCTION__);
511*ec779b8eSAndroid Build Coastguard Worker 
512*ec779b8eSAndroid Build Coastguard Worker     std::shared_ptr<ndk::ScopedAParcel> pauseStates;
513*ec779b8eSAndroid Build Coastguard Worker     media_status_t err = mTranscoder->pause(&pauseStates);
514*ec779b8eSAndroid Build Coastguard Worker     logSessionEnded(TranscodingLogger::SessionEndedReason::PAUSED, err);
515*ec779b8eSAndroid Build Coastguard Worker     if (err != AMEDIA_OK) {
516*ec779b8eSAndroid Build Coastguard Worker         ALOGE("%s: failed to pause transcoder: %d", __FUNCTION__, err);
517*ec779b8eSAndroid Build Coastguard Worker         return err;
518*ec779b8eSAndroid Build Coastguard Worker     }
519*ec779b8eSAndroid Build Coastguard Worker     mPausedStateMap[SessionKeyType(clientId, sessionId)] = pauseStates;
520*ec779b8eSAndroid Build Coastguard Worker 
521*ec779b8eSAndroid Build Coastguard Worker     ALOGI("%s: transcoder paused", __FUNCTION__);
522*ec779b8eSAndroid Build Coastguard Worker     return AMEDIA_OK;
523*ec779b8eSAndroid Build Coastguard Worker }
524*ec779b8eSAndroid Build Coastguard Worker 
handleResume(ClientIdType clientId,SessionIdType sessionId,const TranscodingRequestParcel & request,uid_t callingUid,const std::shared_ptr<ITranscodingClientCallback> & clientCb)525*ec779b8eSAndroid Build Coastguard Worker media_status_t TranscoderWrapper::handleResume(
526*ec779b8eSAndroid Build Coastguard Worker         ClientIdType clientId, SessionIdType sessionId, const TranscodingRequestParcel& request,
527*ec779b8eSAndroid Build Coastguard Worker         uid_t callingUid, const std::shared_ptr<ITranscodingClientCallback>& clientCb) {
528*ec779b8eSAndroid Build Coastguard Worker     std::shared_ptr<ndk::ScopedAParcel> pausedState;
529*ec779b8eSAndroid Build Coastguard Worker     auto it = mPausedStateMap.find(SessionKeyType(clientId, sessionId));
530*ec779b8eSAndroid Build Coastguard Worker     if (it != mPausedStateMap.end()) {
531*ec779b8eSAndroid Build Coastguard Worker         pausedState = it->second;
532*ec779b8eSAndroid Build Coastguard Worker         mPausedStateMap.erase(it);
533*ec779b8eSAndroid Build Coastguard Worker     } else {
534*ec779b8eSAndroid Build Coastguard Worker         ALOGE("%s: can't find paused state", __FUNCTION__);
535*ec779b8eSAndroid Build Coastguard Worker         return AMEDIA_ERROR_INVALID_OPERATION;
536*ec779b8eSAndroid Build Coastguard Worker     }
537*ec779b8eSAndroid Build Coastguard Worker 
538*ec779b8eSAndroid Build Coastguard Worker     ALOGI("%s: setting up transcoder for resume", __FUNCTION__);
539*ec779b8eSAndroid Build Coastguard Worker     TranscodingLogger::SessionEndedReason reason = TranscodingLogger::SessionEndedReason::UNKNOWN;
540*ec779b8eSAndroid Build Coastguard Worker     media_status_t err = setupTranscoder(clientId, sessionId, request, callingUid, clientCb,
541*ec779b8eSAndroid Build Coastguard Worker                                          &reason, pausedState);
542*ec779b8eSAndroid Build Coastguard Worker     if (err != AMEDIA_OK) {
543*ec779b8eSAndroid Build Coastguard Worker         ALOGE("%s: failed to setup transcoder: %d", __FUNCTION__, err);
544*ec779b8eSAndroid Build Coastguard Worker         logSessionEnded(reason, err);
545*ec779b8eSAndroid Build Coastguard Worker         return err;
546*ec779b8eSAndroid Build Coastguard Worker     }
547*ec779b8eSAndroid Build Coastguard Worker 
548*ec779b8eSAndroid Build Coastguard Worker     // Note: For now resume() will just restart transcoding from the beginning, so there is no need
549*ec779b8eSAndroid Build Coastguard Worker     // to distinguish between resume and start from a performance perspective.
550*ec779b8eSAndroid Build Coastguard Worker     mTranscodeStartTime = std::chrono::steady_clock::now();
551*ec779b8eSAndroid Build Coastguard Worker 
552*ec779b8eSAndroid Build Coastguard Worker     err = mTranscoder->resume();
553*ec779b8eSAndroid Build Coastguard Worker     if (err != AMEDIA_OK) {
554*ec779b8eSAndroid Build Coastguard Worker         ALOGE("%s: failed to resume transcoder: %d", __FUNCTION__, err);
555*ec779b8eSAndroid Build Coastguard Worker         logSessionEnded(TranscodingLogger::SessionEndedReason::RESUME_FAILED, err);
556*ec779b8eSAndroid Build Coastguard Worker         return err;
557*ec779b8eSAndroid Build Coastguard Worker     }
558*ec779b8eSAndroid Build Coastguard Worker 
559*ec779b8eSAndroid Build Coastguard Worker     ALOGI("%s: transcoder resumed", __FUNCTION__);
560*ec779b8eSAndroid Build Coastguard Worker     return AMEDIA_OK;
561*ec779b8eSAndroid Build Coastguard Worker }
562*ec779b8eSAndroid Build Coastguard Worker 
cleanup()563*ec779b8eSAndroid Build Coastguard Worker void TranscoderWrapper::cleanup() {
564*ec779b8eSAndroid Build Coastguard Worker     mCurrentClientId = 0;
565*ec779b8eSAndroid Build Coastguard Worker     mCurrentSessionId = -1;
566*ec779b8eSAndroid Build Coastguard Worker     mCurrentCallingUid = -1;
567*ec779b8eSAndroid Build Coastguard Worker     mTranscoderCb = nullptr;
568*ec779b8eSAndroid Build Coastguard Worker     mTranscoder = nullptr;
569*ec779b8eSAndroid Build Coastguard Worker     mSrcFormat = nullptr;
570*ec779b8eSAndroid Build Coastguard Worker     mDstFormat = nullptr;
571*ec779b8eSAndroid Build Coastguard Worker }
572*ec779b8eSAndroid Build Coastguard Worker 
logSessionEnded(const TranscodingLogger::SessionEndedReason & reason,int error)573*ec779b8eSAndroid Build Coastguard Worker void TranscoderWrapper::logSessionEnded(const TranscodingLogger::SessionEndedReason& reason,
574*ec779b8eSAndroid Build Coastguard Worker                                         int error) {
575*ec779b8eSAndroid Build Coastguard Worker     std::chrono::microseconds transcodeDuration(-1);
576*ec779b8eSAndroid Build Coastguard Worker     if (reason == TranscodingLogger::SessionEndedReason::FINISHED && error == AMEDIA_OK) {
577*ec779b8eSAndroid Build Coastguard Worker         transcodeDuration = std::chrono::duration_cast<std::chrono::microseconds>(
578*ec779b8eSAndroid Build Coastguard Worker                 std::chrono::steady_clock::now() - mTranscodeStartTime);
579*ec779b8eSAndroid Build Coastguard Worker     }
580*ec779b8eSAndroid Build Coastguard Worker 
581*ec779b8eSAndroid Build Coastguard Worker     mLogger->logSessionEnded(reason, mCurrentCallingUid, error, transcodeDuration, mSrcFormat.get(),
582*ec779b8eSAndroid Build Coastguard Worker                              mDstFormat.get());
583*ec779b8eSAndroid Build Coastguard Worker }
584*ec779b8eSAndroid Build Coastguard Worker 
queueEvent(Event::Type type,ClientIdType clientId,SessionIdType sessionId,const std::function<void ()> runnable,int32_t arg)585*ec779b8eSAndroid Build Coastguard Worker void TranscoderWrapper::queueEvent(Event::Type type, ClientIdType clientId, SessionIdType sessionId,
586*ec779b8eSAndroid Build Coastguard Worker                                    const std::function<void()> runnable, int32_t arg) {
587*ec779b8eSAndroid Build Coastguard Worker     std::scoped_lock lock{mLock};
588*ec779b8eSAndroid Build Coastguard Worker 
589*ec779b8eSAndroid Build Coastguard Worker     if (!mLooperReady) {
590*ec779b8eSAndroid Build Coastguard Worker         // A shared_ptr to ourselves is given to the thread's stack, so that the TranscoderWrapper
591*ec779b8eSAndroid Build Coastguard Worker         // object doesn't go away until the thread exits. When a watchdog timeout happens, this
592*ec779b8eSAndroid Build Coastguard Worker         // allows the session controller to release its reference to the TranscoderWrapper object
593*ec779b8eSAndroid Build Coastguard Worker         // without blocking on the thread exits.
594*ec779b8eSAndroid Build Coastguard Worker         std::thread([owner = shared_from_this()]() { owner->threadLoop(); }).detach();
595*ec779b8eSAndroid Build Coastguard Worker         mLooperReady = true;
596*ec779b8eSAndroid Build Coastguard Worker     }
597*ec779b8eSAndroid Build Coastguard Worker 
598*ec779b8eSAndroid Build Coastguard Worker     mQueue.push_back({type, clientId, sessionId, runnable, arg});
599*ec779b8eSAndroid Build Coastguard Worker     mCondition.notify_one();
600*ec779b8eSAndroid Build Coastguard Worker }
601*ec779b8eSAndroid Build Coastguard Worker 
threadLoop()602*ec779b8eSAndroid Build Coastguard Worker void TranscoderWrapper::threadLoop() {
603*ec779b8eSAndroid Build Coastguard Worker     androidSetThreadPriority(0 /*tid (0 = current) */, ANDROID_PRIORITY_BACKGROUND);
604*ec779b8eSAndroid Build Coastguard Worker     std::unique_lock<std::mutex> lock{mLock};
605*ec779b8eSAndroid Build Coastguard Worker     // TranscoderWrapper currently lives in the transcoding service, as long as
606*ec779b8eSAndroid Build Coastguard Worker     // MediaTranscodingService itself.
607*ec779b8eSAndroid Build Coastguard Worker     while (true) {
608*ec779b8eSAndroid Build Coastguard Worker         // Wait for the next event.
609*ec779b8eSAndroid Build Coastguard Worker         while (mQueue.empty()) {
610*ec779b8eSAndroid Build Coastguard Worker             mCondition.wait(lock);
611*ec779b8eSAndroid Build Coastguard Worker         }
612*ec779b8eSAndroid Build Coastguard Worker 
613*ec779b8eSAndroid Build Coastguard Worker         Event event = *mQueue.begin();
614*ec779b8eSAndroid Build Coastguard Worker         mQueue.pop_front();
615*ec779b8eSAndroid Build Coastguard Worker 
616*ec779b8eSAndroid Build Coastguard Worker         ALOGV("%s: %s", __FUNCTION__, toString(event).c_str());
617*ec779b8eSAndroid Build Coastguard Worker 
618*ec779b8eSAndroid Build Coastguard Worker         if (event.type == Event::Abandon) {
619*ec779b8eSAndroid Build Coastguard Worker             break;
620*ec779b8eSAndroid Build Coastguard Worker         }
621*ec779b8eSAndroid Build Coastguard Worker 
622*ec779b8eSAndroid Build Coastguard Worker         lock.unlock();
623*ec779b8eSAndroid Build Coastguard Worker         event.runnable();
624*ec779b8eSAndroid Build Coastguard Worker         lock.lock();
625*ec779b8eSAndroid Build Coastguard Worker     }
626*ec779b8eSAndroid Build Coastguard Worker }
627*ec779b8eSAndroid Build Coastguard Worker }  // namespace android
628