xref: /aosp_15_r20/frameworks/av/media/module/service.mediatranscoding/SimulatedTranscoder.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 "SimulatedTranscoder"
19*ec779b8eSAndroid Build Coastguard Worker #include "SimulatedTranscoder.h"
20*ec779b8eSAndroid Build Coastguard Worker 
21*ec779b8eSAndroid Build Coastguard Worker #include <utils/Log.h>
22*ec779b8eSAndroid Build Coastguard Worker 
23*ec779b8eSAndroid Build Coastguard Worker #include <thread>
24*ec779b8eSAndroid Build Coastguard Worker 
25*ec779b8eSAndroid Build Coastguard Worker namespace android {
26*ec779b8eSAndroid Build Coastguard Worker 
27*ec779b8eSAndroid Build Coastguard Worker //static
toString(Event::Type type)28*ec779b8eSAndroid Build Coastguard Worker const char* SimulatedTranscoder::toString(Event::Type type) {
29*ec779b8eSAndroid Build Coastguard Worker     switch (type) {
30*ec779b8eSAndroid Build Coastguard Worker     case Event::Start:
31*ec779b8eSAndroid Build Coastguard Worker         return "Start";
32*ec779b8eSAndroid Build Coastguard Worker     case Event::Pause:
33*ec779b8eSAndroid Build Coastguard Worker         return "Pause";
34*ec779b8eSAndroid Build Coastguard Worker     case Event::Resume:
35*ec779b8eSAndroid Build Coastguard Worker         return "Resume";
36*ec779b8eSAndroid Build Coastguard Worker     case Event::Stop:
37*ec779b8eSAndroid Build Coastguard Worker         return "Stop";
38*ec779b8eSAndroid Build Coastguard Worker     case Event::Finished:
39*ec779b8eSAndroid Build Coastguard Worker         return "Finished";
40*ec779b8eSAndroid Build Coastguard Worker     case Event::Failed:
41*ec779b8eSAndroid Build Coastguard Worker         return "Failed";
42*ec779b8eSAndroid Build Coastguard Worker     case Event::Abandon:
43*ec779b8eSAndroid Build Coastguard Worker         return "Abandon";
44*ec779b8eSAndroid Build Coastguard Worker     default:
45*ec779b8eSAndroid Build Coastguard Worker         break;
46*ec779b8eSAndroid Build Coastguard Worker     }
47*ec779b8eSAndroid Build Coastguard Worker     return "(unknown)";
48*ec779b8eSAndroid Build Coastguard Worker }
49*ec779b8eSAndroid Build Coastguard Worker 
SimulatedTranscoder(const std::shared_ptr<TranscoderCallbackInterface> & cb)50*ec779b8eSAndroid Build Coastguard Worker SimulatedTranscoder::SimulatedTranscoder(const std::shared_ptr<TranscoderCallbackInterface>& cb)
51*ec779b8eSAndroid Build Coastguard Worker       : mCallback(cb), mLooperReady(false) {
52*ec779b8eSAndroid Build Coastguard Worker     ALOGV("SimulatedTranscoder CTOR: %p", this);
53*ec779b8eSAndroid Build Coastguard Worker }
54*ec779b8eSAndroid Build Coastguard Worker 
~SimulatedTranscoder()55*ec779b8eSAndroid Build Coastguard Worker SimulatedTranscoder::~SimulatedTranscoder() {
56*ec779b8eSAndroid Build Coastguard Worker     ALOGV("SimulatedTranscoder DTOR: %p", this);
57*ec779b8eSAndroid Build Coastguard Worker }
58*ec779b8eSAndroid Build Coastguard Worker 
start(ClientIdType clientId,SessionIdType sessionId,const TranscodingRequestParcel & request,uid_t,const std::shared_ptr<ITranscodingClientCallback> &)59*ec779b8eSAndroid Build Coastguard Worker void SimulatedTranscoder::start(
60*ec779b8eSAndroid Build Coastguard Worker         ClientIdType clientId, SessionIdType sessionId, const TranscodingRequestParcel& request,
61*ec779b8eSAndroid Build Coastguard Worker         uid_t /*callingUid*/,
62*ec779b8eSAndroid Build Coastguard Worker         const std::shared_ptr<ITranscodingClientCallback>& /*clientCallback*/) {
63*ec779b8eSAndroid Build Coastguard Worker     {
64*ec779b8eSAndroid Build Coastguard Worker         auto lock = std::scoped_lock(mLock);
65*ec779b8eSAndroid Build Coastguard Worker         int64_t processingTimeUs = kSessionDurationUs;
66*ec779b8eSAndroid Build Coastguard Worker         if (request.testConfig.has_value() && request.testConfig->processingTotalTimeMs > 0) {
67*ec779b8eSAndroid Build Coastguard Worker             processingTimeUs = request.testConfig->processingTotalTimeMs * 1000;
68*ec779b8eSAndroid Build Coastguard Worker         }
69*ec779b8eSAndroid Build Coastguard Worker         ALOGI("%s: session {%lld, %d}: processingTimeUs: %lld", __FUNCTION__, (long long)clientId,
70*ec779b8eSAndroid Build Coastguard Worker               sessionId, (long long)processingTimeUs);
71*ec779b8eSAndroid Build Coastguard Worker         SessionKeyType key = std::make_pair(clientId, sessionId);
72*ec779b8eSAndroid Build Coastguard Worker         mRemainingTimeMap.emplace(key, processingTimeUs);
73*ec779b8eSAndroid Build Coastguard Worker     }
74*ec779b8eSAndroid Build Coastguard Worker 
75*ec779b8eSAndroid Build Coastguard Worker     queueEvent(Event::Start, clientId, sessionId, [=] {
76*ec779b8eSAndroid Build Coastguard Worker         auto callback = mCallback.lock();
77*ec779b8eSAndroid Build Coastguard Worker         if (callback != nullptr) {
78*ec779b8eSAndroid Build Coastguard Worker             callback->onStarted(clientId, sessionId);
79*ec779b8eSAndroid Build Coastguard Worker         }
80*ec779b8eSAndroid Build Coastguard Worker     });
81*ec779b8eSAndroid Build Coastguard Worker }
82*ec779b8eSAndroid Build Coastguard Worker 
pause(ClientIdType clientId,SessionIdType sessionId)83*ec779b8eSAndroid Build Coastguard Worker void SimulatedTranscoder::pause(ClientIdType clientId, SessionIdType sessionId) {
84*ec779b8eSAndroid Build Coastguard Worker     queueEvent(Event::Pause, clientId, sessionId, [=] {
85*ec779b8eSAndroid Build Coastguard Worker         auto callback = mCallback.lock();
86*ec779b8eSAndroid Build Coastguard Worker         if (callback != nullptr) {
87*ec779b8eSAndroid Build Coastguard Worker             callback->onPaused(clientId, sessionId);
88*ec779b8eSAndroid Build Coastguard Worker         }
89*ec779b8eSAndroid Build Coastguard Worker     });
90*ec779b8eSAndroid Build Coastguard Worker }
91*ec779b8eSAndroid Build Coastguard Worker 
resume(ClientIdType clientId,SessionIdType sessionId,const TranscodingRequestParcel &,uid_t,const std::shared_ptr<ITranscodingClientCallback> &)92*ec779b8eSAndroid Build Coastguard Worker void SimulatedTranscoder::resume(
93*ec779b8eSAndroid Build Coastguard Worker         ClientIdType clientId, SessionIdType sessionId, const TranscodingRequestParcel& /*request*/,
94*ec779b8eSAndroid Build Coastguard Worker         uid_t /*callingUid*/,
95*ec779b8eSAndroid Build Coastguard Worker         const std::shared_ptr<ITranscodingClientCallback>& /*clientCallback*/) {
96*ec779b8eSAndroid Build Coastguard Worker     queueEvent(Event::Resume, clientId, sessionId, [=] {
97*ec779b8eSAndroid Build Coastguard Worker         auto callback = mCallback.lock();
98*ec779b8eSAndroid Build Coastguard Worker         if (callback != nullptr) {
99*ec779b8eSAndroid Build Coastguard Worker             callback->onResumed(clientId, sessionId);
100*ec779b8eSAndroid Build Coastguard Worker         }
101*ec779b8eSAndroid Build Coastguard Worker     });
102*ec779b8eSAndroid Build Coastguard Worker }
103*ec779b8eSAndroid Build Coastguard Worker 
stop(ClientIdType clientId,SessionIdType sessionId,bool abandon)104*ec779b8eSAndroid Build Coastguard Worker void SimulatedTranscoder::stop(ClientIdType clientId, SessionIdType sessionId, bool abandon) {
105*ec779b8eSAndroid Build Coastguard Worker     queueEvent(Event::Stop, clientId, sessionId, nullptr);
106*ec779b8eSAndroid Build Coastguard Worker 
107*ec779b8eSAndroid Build Coastguard Worker     if (abandon) {
108*ec779b8eSAndroid Build Coastguard Worker         queueEvent(Event::Abandon, 0, 0, nullptr);
109*ec779b8eSAndroid Build Coastguard Worker     }
110*ec779b8eSAndroid Build Coastguard Worker }
111*ec779b8eSAndroid Build Coastguard Worker 
queueEvent(Event::Type type,ClientIdType clientId,SessionIdType sessionId,std::function<void ()> runnable)112*ec779b8eSAndroid Build Coastguard Worker void SimulatedTranscoder::queueEvent(Event::Type type, ClientIdType clientId,
113*ec779b8eSAndroid Build Coastguard Worker                                      SessionIdType sessionId, std::function<void()> runnable) {
114*ec779b8eSAndroid Build Coastguard Worker     ALOGV("%s: session {%lld, %d}: %s", __FUNCTION__, (long long)clientId, sessionId,
115*ec779b8eSAndroid Build Coastguard Worker           toString(type));
116*ec779b8eSAndroid Build Coastguard Worker 
117*ec779b8eSAndroid Build Coastguard Worker     auto lock = std::scoped_lock(mLock);
118*ec779b8eSAndroid Build Coastguard Worker 
119*ec779b8eSAndroid Build Coastguard Worker     if (!mLooperReady) {
120*ec779b8eSAndroid Build Coastguard Worker         // A shared_ptr to ourselves is given to the thread's stack, so that SimulatedTranscoder
121*ec779b8eSAndroid Build Coastguard Worker         // object doesn't go away until the thread exits. When a watchdog timeout happens, this
122*ec779b8eSAndroid Build Coastguard Worker         // allows the session controller to release its reference to the TranscoderWrapper object
123*ec779b8eSAndroid Build Coastguard Worker         // without blocking on the thread exits.
124*ec779b8eSAndroid Build Coastguard Worker         std::thread([owner = shared_from_this()]() { owner->threadLoop(); }).detach();
125*ec779b8eSAndroid Build Coastguard Worker         mLooperReady = true;
126*ec779b8eSAndroid Build Coastguard Worker     }
127*ec779b8eSAndroid Build Coastguard Worker 
128*ec779b8eSAndroid Build Coastguard Worker     mQueue.push_back({type, clientId, sessionId, runnable});
129*ec779b8eSAndroid Build Coastguard Worker     mCondition.notify_one();
130*ec779b8eSAndroid Build Coastguard Worker }
131*ec779b8eSAndroid Build Coastguard Worker 
threadLoop()132*ec779b8eSAndroid Build Coastguard Worker void SimulatedTranscoder::threadLoop() {
133*ec779b8eSAndroid Build Coastguard Worker     bool running = false;
134*ec779b8eSAndroid Build Coastguard Worker     std::chrono::steady_clock::time_point lastRunningTime;
135*ec779b8eSAndroid Build Coastguard Worker     Event lastRunningEvent;
136*ec779b8eSAndroid Build Coastguard Worker 
137*ec779b8eSAndroid Build Coastguard Worker     std::unique_lock<std::mutex> lock(mLock);
138*ec779b8eSAndroid Build Coastguard Worker     // SimulatedTranscoder currently lives in the transcoding service, as long as
139*ec779b8eSAndroid Build Coastguard Worker     // MediaTranscodingService itself.
140*ec779b8eSAndroid Build Coastguard Worker     while (true) {
141*ec779b8eSAndroid Build Coastguard Worker         // Wait for the next event.
142*ec779b8eSAndroid Build Coastguard Worker         while (mQueue.empty()) {
143*ec779b8eSAndroid Build Coastguard Worker             if (!running) {
144*ec779b8eSAndroid Build Coastguard Worker                 mCondition.wait(lock);
145*ec779b8eSAndroid Build Coastguard Worker                 continue;
146*ec779b8eSAndroid Build Coastguard Worker             }
147*ec779b8eSAndroid Build Coastguard Worker             // If running, wait for the remaining life of this session. Report finish if timed out.
148*ec779b8eSAndroid Build Coastguard Worker             SessionKeyType key =
149*ec779b8eSAndroid Build Coastguard Worker                     std::make_pair(lastRunningEvent.clientId, lastRunningEvent.sessionId);
150*ec779b8eSAndroid Build Coastguard Worker             std::cv_status status = mCondition.wait_for(lock, mRemainingTimeMap[key]);
151*ec779b8eSAndroid Build Coastguard Worker             if (status == std::cv_status::timeout) {
152*ec779b8eSAndroid Build Coastguard Worker                 running = false;
153*ec779b8eSAndroid Build Coastguard Worker 
154*ec779b8eSAndroid Build Coastguard Worker                 auto callback = mCallback.lock();
155*ec779b8eSAndroid Build Coastguard Worker                 if (callback != nullptr) {
156*ec779b8eSAndroid Build Coastguard Worker                     mRemainingTimeMap.erase(key);
157*ec779b8eSAndroid Build Coastguard Worker 
158*ec779b8eSAndroid Build Coastguard Worker                     lock.unlock();
159*ec779b8eSAndroid Build Coastguard Worker                     callback->onFinish(lastRunningEvent.clientId, lastRunningEvent.sessionId);
160*ec779b8eSAndroid Build Coastguard Worker                     lock.lock();
161*ec779b8eSAndroid Build Coastguard Worker                 }
162*ec779b8eSAndroid Build Coastguard Worker             } else {
163*ec779b8eSAndroid Build Coastguard Worker                 // Advance last running time and remaining time. This is needed to guard
164*ec779b8eSAndroid Build Coastguard Worker                 // against bad events (which will be ignored) or spurious wakeups, in that
165*ec779b8eSAndroid Build Coastguard Worker                 // case we don't want to wait for the same time again.
166*ec779b8eSAndroid Build Coastguard Worker                 auto now = std::chrono::steady_clock::now();
167*ec779b8eSAndroid Build Coastguard Worker                 mRemainingTimeMap[key] -= std::chrono::duration_cast<std::chrono::microseconds>(
168*ec779b8eSAndroid Build Coastguard Worker                         now - lastRunningTime);
169*ec779b8eSAndroid Build Coastguard Worker                 lastRunningTime = now;
170*ec779b8eSAndroid Build Coastguard Worker             }
171*ec779b8eSAndroid Build Coastguard Worker         }
172*ec779b8eSAndroid Build Coastguard Worker 
173*ec779b8eSAndroid Build Coastguard Worker         // Handle the events, adjust state and send updates to client accordingly.
174*ec779b8eSAndroid Build Coastguard Worker         Event event = *mQueue.begin();
175*ec779b8eSAndroid Build Coastguard Worker         mQueue.pop_front();
176*ec779b8eSAndroid Build Coastguard Worker 
177*ec779b8eSAndroid Build Coastguard Worker         ALOGD("%s: session {%lld, %d}: %s", __FUNCTION__, (long long)event.clientId,
178*ec779b8eSAndroid Build Coastguard Worker               event.sessionId, toString(event.type));
179*ec779b8eSAndroid Build Coastguard Worker 
180*ec779b8eSAndroid Build Coastguard Worker         if (event.type == Event::Abandon) {
181*ec779b8eSAndroid Build Coastguard Worker             break;
182*ec779b8eSAndroid Build Coastguard Worker         }
183*ec779b8eSAndroid Build Coastguard Worker 
184*ec779b8eSAndroid Build Coastguard Worker         SessionKeyType key = std::make_pair(event.clientId, event.sessionId);
185*ec779b8eSAndroid Build Coastguard Worker         if (!running && (event.type == Event::Start || event.type == Event::Resume)) {
186*ec779b8eSAndroid Build Coastguard Worker             running = true;
187*ec779b8eSAndroid Build Coastguard Worker             lastRunningTime = std::chrono::steady_clock::now();
188*ec779b8eSAndroid Build Coastguard Worker             lastRunningEvent = event;
189*ec779b8eSAndroid Build Coastguard Worker             ALOGV("%s: session {%lld, %d}: remaining time: %lld", __FUNCTION__,
190*ec779b8eSAndroid Build Coastguard Worker                   (long long)event.clientId, event.sessionId,
191*ec779b8eSAndroid Build Coastguard Worker                   (long long)mRemainingTimeMap[key].count());
192*ec779b8eSAndroid Build Coastguard Worker 
193*ec779b8eSAndroid Build Coastguard Worker         } else if (running && (event.type == Event::Pause || event.type == Event::Stop)) {
194*ec779b8eSAndroid Build Coastguard Worker             running = false;
195*ec779b8eSAndroid Build Coastguard Worker             if (event.type == Event::Stop) {
196*ec779b8eSAndroid Build Coastguard Worker                 mRemainingTimeMap.erase(key);
197*ec779b8eSAndroid Build Coastguard Worker             } else {
198*ec779b8eSAndroid Build Coastguard Worker                 mRemainingTimeMap[key] -= std::chrono::duration_cast<std::chrono::microseconds>(
199*ec779b8eSAndroid Build Coastguard Worker                         std::chrono::steady_clock::now() - lastRunningTime);
200*ec779b8eSAndroid Build Coastguard Worker             }
201*ec779b8eSAndroid Build Coastguard Worker         } else {
202*ec779b8eSAndroid Build Coastguard Worker             ALOGW("%s: discarding bad event: session {%lld, %d}: %s", __FUNCTION__,
203*ec779b8eSAndroid Build Coastguard Worker                   (long long)event.clientId, event.sessionId, toString(event.type));
204*ec779b8eSAndroid Build Coastguard Worker             continue;
205*ec779b8eSAndroid Build Coastguard Worker         }
206*ec779b8eSAndroid Build Coastguard Worker 
207*ec779b8eSAndroid Build Coastguard Worker         if (event.runnable != nullptr) {
208*ec779b8eSAndroid Build Coastguard Worker             lock.unlock();
209*ec779b8eSAndroid Build Coastguard Worker             event.runnable();
210*ec779b8eSAndroid Build Coastguard Worker             lock.lock();
211*ec779b8eSAndroid Build Coastguard Worker         }
212*ec779b8eSAndroid Build Coastguard Worker     }
213*ec779b8eSAndroid Build Coastguard Worker }
214*ec779b8eSAndroid Build Coastguard Worker 
215*ec779b8eSAndroid Build Coastguard Worker }  // namespace android
216