| Chong Zhang | 7522218 | 2020-04-29 14:43:42 -0700 | [diff] [blame] | 1 | /* | 
 | 2 |  * Copyright (C) 2020 The Android Open Source Project | 
 | 3 |  * | 
 | 4 |  * Licensed under the Apache License, Version 2.0 (the "License"); | 
 | 5 |  * you may not use this file except in compliance with the License. | 
 | 6 |  * You may obtain a copy of the License at | 
 | 7 |  * | 
 | 8 |  *      http://www.apache.org/licenses/LICENSE-2.0 | 
 | 9 |  * | 
 | 10 |  * Unless required by applicable law or agreed to in writing, software | 
 | 11 |  * distributed under the License is distributed on an "AS IS" BASIS, | 
 | 12 |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 | 13 |  * See the License for the specific language governing permissions and | 
 | 14 |  * limitations under the License. | 
 | 15 |  */ | 
 | 16 |  | 
 | 17 | //#define LOG_NDEBUG 0 | 
 | 18 | #define LOG_TAG "SimulatedTranscoder" | 
 | 19 | #include "SimulatedTranscoder.h" | 
 | 20 |  | 
 | 21 | #include <utils/Log.h> | 
 | 22 |  | 
 | 23 | #include <thread> | 
 | 24 |  | 
 | 25 | namespace android { | 
 | 26 |  | 
 | 27 | //static | 
 | 28 | const char* SimulatedTranscoder::toString(Event::Type type) { | 
 | 29 |     switch (type) { | 
 | 30 |     case Event::Start: | 
 | 31 |         return "Start"; | 
 | 32 |     case Event::Pause: | 
 | 33 |         return "Pause"; | 
 | 34 |     case Event::Resume: | 
 | 35 |         return "Resume"; | 
 | 36 |     default: | 
 | 37 |         break; | 
 | 38 |     } | 
 | 39 |     return "(unknown)"; | 
 | 40 | } | 
 | 41 |  | 
 | 42 | SimulatedTranscoder::SimulatedTranscoder() { | 
 | 43 |     std::thread(&SimulatedTranscoder::threadLoop, this).detach(); | 
 | 44 | } | 
 | 45 |  | 
 | 46 | void SimulatedTranscoder::setCallback(const std::shared_ptr<TranscoderCallbackInterface>& cb) { | 
 | 47 |     mCallback = cb; | 
 | 48 | } | 
 | 49 |  | 
| Chong Zhang | 6646927 | 2020-06-04 16:51:55 -0700 | [diff] [blame] | 50 | void SimulatedTranscoder::start( | 
| Chong Zhang | bc06248 | 2020-10-14 16:43:53 -0700 | [diff] [blame] | 51 |         ClientIdType clientId, SessionIdType sessionId, const TranscodingRequestParcel& request, | 
| Chong Zhang | 6646927 | 2020-06-04 16:51:55 -0700 | [diff] [blame] | 52 |         const std::shared_ptr<ITranscodingClientCallback>& /*clientCallback*/) { | 
| hkuang | 34915b1 | 2020-06-18 09:36:39 -0700 | [diff] [blame] | 53 |     if (request.testConfig.has_value() && request.testConfig->processingTotalTimeMs > 0) { | 
| Chong Zhang | bc06248 | 2020-10-14 16:43:53 -0700 | [diff] [blame] | 54 |         mSessionProcessingTimeMs = request.testConfig->processingTotalTimeMs; | 
| hkuang | a9ffd59 | 2020-06-05 10:38:02 -0700 | [diff] [blame] | 55 |     } | 
| Chong Zhang | bc06248 | 2020-10-14 16:43:53 -0700 | [diff] [blame] | 56 |     ALOGV("%s: session {%d}: processingTime: %lld", __FUNCTION__, sessionId, | 
 | 57 |           (long long)mSessionProcessingTimeMs); | 
 | 58 |     queueEvent(Event::Start, clientId, sessionId, [=] { | 
| Chong Zhang | de60f06 | 2020-06-11 17:05:10 -0700 | [diff] [blame] | 59 |         auto callback = mCallback.lock(); | 
 | 60 |         if (callback != nullptr) { | 
| Chong Zhang | bc06248 | 2020-10-14 16:43:53 -0700 | [diff] [blame] | 61 |             callback->onStarted(clientId, sessionId); | 
| Chong Zhang | de60f06 | 2020-06-11 17:05:10 -0700 | [diff] [blame] | 62 |         } | 
 | 63 |     }); | 
| Chong Zhang | 7522218 | 2020-04-29 14:43:42 -0700 | [diff] [blame] | 64 | } | 
 | 65 |  | 
| Chong Zhang | bc06248 | 2020-10-14 16:43:53 -0700 | [diff] [blame] | 66 | void SimulatedTranscoder::pause(ClientIdType clientId, SessionIdType sessionId) { | 
 | 67 |     queueEvent(Event::Pause, clientId, sessionId, [=] { | 
| Chong Zhang | de60f06 | 2020-06-11 17:05:10 -0700 | [diff] [blame] | 68 |         auto callback = mCallback.lock(); | 
 | 69 |         if (callback != nullptr) { | 
| Chong Zhang | bc06248 | 2020-10-14 16:43:53 -0700 | [diff] [blame] | 70 |             callback->onPaused(clientId, sessionId); | 
| Chong Zhang | de60f06 | 2020-06-11 17:05:10 -0700 | [diff] [blame] | 71 |         } | 
 | 72 |     }); | 
| Chong Zhang | 7522218 | 2020-04-29 14:43:42 -0700 | [diff] [blame] | 73 | } | 
 | 74 |  | 
| Chong Zhang | b55c545 | 2020-06-26 14:32:12 -0700 | [diff] [blame] | 75 | void SimulatedTranscoder::resume( | 
| Chong Zhang | bc06248 | 2020-10-14 16:43:53 -0700 | [diff] [blame] | 76 |         ClientIdType clientId, SessionIdType sessionId, const TranscodingRequestParcel& /*request*/, | 
| Chong Zhang | b55c545 | 2020-06-26 14:32:12 -0700 | [diff] [blame] | 77 |         const std::shared_ptr<ITranscodingClientCallback>& /*clientCallback*/) { | 
| Chong Zhang | bc06248 | 2020-10-14 16:43:53 -0700 | [diff] [blame] | 78 |     queueEvent(Event::Resume, clientId, sessionId, [=] { | 
| Chong Zhang | de60f06 | 2020-06-11 17:05:10 -0700 | [diff] [blame] | 79 |         auto callback = mCallback.lock(); | 
 | 80 |         if (callback != nullptr) { | 
| Chong Zhang | bc06248 | 2020-10-14 16:43:53 -0700 | [diff] [blame] | 81 |             callback->onResumed(clientId, sessionId); | 
| Chong Zhang | de60f06 | 2020-06-11 17:05:10 -0700 | [diff] [blame] | 82 |         } | 
 | 83 |     }); | 
| Chong Zhang | 7522218 | 2020-04-29 14:43:42 -0700 | [diff] [blame] | 84 | } | 
 | 85 |  | 
| Chong Zhang | bc06248 | 2020-10-14 16:43:53 -0700 | [diff] [blame] | 86 | void SimulatedTranscoder::stop(ClientIdType clientId, SessionIdType sessionId) { | 
 | 87 |     queueEvent(Event::Stop, clientId, sessionId, nullptr); | 
| Chong Zhang | 00feca2 | 2020-05-08 15:02:06 -0700 | [diff] [blame] | 88 | } | 
 | 89 |  | 
| Chong Zhang | bc06248 | 2020-10-14 16:43:53 -0700 | [diff] [blame] | 90 | void SimulatedTranscoder::queueEvent(Event::Type type, ClientIdType clientId, | 
 | 91 |                                      SessionIdType sessionId, std::function<void()> runnable) { | 
 | 92 |     ALOGV("%s: session {%lld, %d}: %s", __FUNCTION__, (long long)clientId, sessionId, | 
 | 93 |           toString(type)); | 
| Chong Zhang | 7522218 | 2020-04-29 14:43:42 -0700 | [diff] [blame] | 94 |  | 
 | 95 |     auto lock = std::scoped_lock(mLock); | 
 | 96 |  | 
| Chong Zhang | bc06248 | 2020-10-14 16:43:53 -0700 | [diff] [blame] | 97 |     mQueue.push_back({type, clientId, sessionId, runnable}); | 
| Chong Zhang | 7522218 | 2020-04-29 14:43:42 -0700 | [diff] [blame] | 98 |     mCondition.notify_one(); | 
 | 99 | } | 
 | 100 |  | 
 | 101 | void SimulatedTranscoder::threadLoop() { | 
 | 102 |     bool running = false; | 
| Chong Zhang | bc06248 | 2020-10-14 16:43:53 -0700 | [diff] [blame] | 103 |     std::chrono::microseconds remainingUs(kSessionDurationUs); | 
| Chong Zhang | 7522218 | 2020-04-29 14:43:42 -0700 | [diff] [blame] | 104 |     std::chrono::system_clock::time_point lastRunningTime; | 
 | 105 |     Event lastRunningEvent; | 
 | 106 |  | 
 | 107 |     std::unique_lock<std::mutex> lock(mLock); | 
 | 108 |     // SimulatedTranscoder currently lives in the transcoding service, as long as | 
 | 109 |     // MediaTranscodingService itself. | 
 | 110 |     while (true) { | 
 | 111 |         // Wait for the next event. | 
 | 112 |         while (mQueue.empty()) { | 
 | 113 |             if (!running) { | 
 | 114 |                 mCondition.wait(lock); | 
 | 115 |                 continue; | 
 | 116 |             } | 
| Chong Zhang | bc06248 | 2020-10-14 16:43:53 -0700 | [diff] [blame] | 117 |             // If running, wait for the remaining life of this session. Report finish if timed out. | 
| Chong Zhang | 7522218 | 2020-04-29 14:43:42 -0700 | [diff] [blame] | 118 |             std::cv_status status = mCondition.wait_for(lock, remainingUs); | 
 | 119 |             if (status == std::cv_status::timeout) { | 
 | 120 |                 running = false; | 
 | 121 |  | 
 | 122 |                 auto callback = mCallback.lock(); | 
 | 123 |                 if (callback != nullptr) { | 
 | 124 |                     lock.unlock(); | 
| Chong Zhang | bc06248 | 2020-10-14 16:43:53 -0700 | [diff] [blame] | 125 |                     callback->onFinish(lastRunningEvent.clientId, lastRunningEvent.sessionId); | 
| Chong Zhang | 7522218 | 2020-04-29 14:43:42 -0700 | [diff] [blame] | 126 |                     lock.lock(); | 
 | 127 |                 } | 
 | 128 |             } else { | 
 | 129 |                 // Advance last running time and remaining time. This is needed to guard | 
 | 130 |                 // against bad events (which will be ignored) or spurious wakeups, in that | 
 | 131 |                 // case we don't want to wait for the same time again. | 
 | 132 |                 auto now = std::chrono::system_clock::now(); | 
 | 133 |                 remainingUs -= (now - lastRunningTime); | 
 | 134 |                 lastRunningTime = now; | 
 | 135 |             } | 
 | 136 |         } | 
 | 137 |  | 
 | 138 |         // Handle the events, adjust state and send updates to client accordingly. | 
 | 139 |         while (!mQueue.empty()) { | 
 | 140 |             Event event = *mQueue.begin(); | 
 | 141 |             mQueue.pop_front(); | 
 | 142 |  | 
| Chong Zhang | bc06248 | 2020-10-14 16:43:53 -0700 | [diff] [blame] | 143 |             ALOGV("%s: session {%lld, %d}: %s", __FUNCTION__, (long long)event.clientId, | 
 | 144 |                   event.sessionId, toString(event.type)); | 
| Chong Zhang | 7522218 | 2020-04-29 14:43:42 -0700 | [diff] [blame] | 145 |  | 
 | 146 |             if (!running && (event.type == Event::Start || event.type == Event::Resume)) { | 
 | 147 |                 running = true; | 
 | 148 |                 lastRunningTime = std::chrono::system_clock::now(); | 
 | 149 |                 lastRunningEvent = event; | 
 | 150 |                 if (event.type == Event::Start) { | 
| Chong Zhang | bc06248 | 2020-10-14 16:43:53 -0700 | [diff] [blame] | 151 |                     remainingUs = std::chrono::milliseconds(mSessionProcessingTimeMs); | 
| Chong Zhang | 7522218 | 2020-04-29 14:43:42 -0700 | [diff] [blame] | 152 |                 } | 
| Chong Zhang | 00feca2 | 2020-05-08 15:02:06 -0700 | [diff] [blame] | 153 |             } else if (running && (event.type == Event::Pause || event.type == Event::Stop)) { | 
| Chong Zhang | 7522218 | 2020-04-29 14:43:42 -0700 | [diff] [blame] | 154 |                 running = false; | 
 | 155 |                 remainingUs -= (std::chrono::system_clock::now() - lastRunningTime); | 
 | 156 |             } else { | 
| Chong Zhang | bc06248 | 2020-10-14 16:43:53 -0700 | [diff] [blame] | 157 |                 ALOGW("%s: discarding bad event: session {%lld, %d}: %s", __FUNCTION__, | 
 | 158 |                       (long long)event.clientId, event.sessionId, toString(event.type)); | 
| Chong Zhang | 7522218 | 2020-04-29 14:43:42 -0700 | [diff] [blame] | 159 |                 continue; | 
 | 160 |             } | 
 | 161 |  | 
| Chong Zhang | de60f06 | 2020-06-11 17:05:10 -0700 | [diff] [blame] | 162 |             if (event.runnable != nullptr) { | 
| Chong Zhang | 7522218 | 2020-04-29 14:43:42 -0700 | [diff] [blame] | 163 |                 lock.unlock(); | 
| Chong Zhang | de60f06 | 2020-06-11 17:05:10 -0700 | [diff] [blame] | 164 |                 event.runnable(); | 
| Chong Zhang | 7522218 | 2020-04-29 14:43:42 -0700 | [diff] [blame] | 165 |                 lock.lock(); | 
 | 166 |             } | 
 | 167 |         } | 
 | 168 |     } | 
 | 169 | } | 
 | 170 |  | 
 | 171 | }  // namespace android |