• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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 #include <cstddef>
18 #include <memory>
19 
20 #define LOG_TAG "AHAL_EffectThread"
21 #include <android-base/logging.h>
22 #include <pthread.h>
23 #include <sys/resource.h>
24 
25 #include "effect-impl/EffectThread.h"
26 #include "effect-impl/EffectTypes.h"
27 
28 using ::android::hardware::EventFlag;
29 
30 namespace aidl::android::hardware::audio::effect {
31 
EffectThread()32 EffectThread::EffectThread() {
33     LOG(DEBUG) << __func__;
34 }
35 
~EffectThread()36 EffectThread::~EffectThread() {
37     destroyThread();
38     LOG(DEBUG) << __func__ << " done";
39 }
40 
createThread(std::shared_ptr<EffectContext> context,const std::string & name,int priority)41 RetCode EffectThread::createThread(std::shared_ptr<EffectContext> context, const std::string& name,
42                                    int priority) {
43     if (mThread.joinable()) {
44         LOG(WARNING) << mName << __func__ << " thread already created, no-op";
45         return RetCode::SUCCESS;
46     }
47     mName = name;
48     mPriority = priority;
49     {
50         std::lock_guard lg(mThreadMutex);
51         mStop = true;
52         mExit = false;
53         mThreadContext = std::move(context);
54         auto statusMQ = mThreadContext->getStatusFmq();
55         EventFlag* efGroup = nullptr;
56         ::android::status_t status =
57                 EventFlag::createEventFlag(statusMQ->getEventFlagWord(), &efGroup);
58         if (status != ::android::OK || !efGroup) {
59             LOG(ERROR) << mName << __func__ << " create EventFlagGroup failed " << status
60                        << " efGroup " << efGroup;
61             return RetCode::ERROR_THREAD;
62         }
63         mEfGroup.reset(efGroup);
64         // kickoff and wait for commands (CommandId::START/STOP) or IEffect.close from client
65         mEfGroup->wake(kEventFlagNotEmpty);
66     }
67 
68     mThread = std::thread(&EffectThread::threadLoop, this);
69     LOG(DEBUG) << mName << __func__ << " priority " << mPriority << " done";
70     return RetCode::SUCCESS;
71 }
72 
destroyThread()73 RetCode EffectThread::destroyThread() {
74     {
75         std::lock_guard lg(mThreadMutex);
76         mStop = mExit = true;
77     }
78     mCv.notify_one();
79 
80     if (mThread.joinable()) {
81         mThread.join();
82     }
83 
84     {
85         std::lock_guard lg(mThreadMutex);
86         mThreadContext.reset();
87     }
88     LOG(DEBUG) << mName << __func__;
89     return RetCode::SUCCESS;
90 }
91 
startThread()92 RetCode EffectThread::startThread() {
93     {
94         std::lock_guard lg(mThreadMutex);
95         mStop = false;
96         mCv.notify_one();
97     }
98 
99     mEfGroup->wake(kEventFlagNotEmpty);
100     LOG(DEBUG) << mName << __func__;
101     return RetCode::SUCCESS;
102 }
103 
stopThread()104 RetCode EffectThread::stopThread() {
105     {
106         std::lock_guard lg(mThreadMutex);
107         mStop = true;
108         mCv.notify_one();
109     }
110 
111     mEfGroup->wake(kEventFlagNotEmpty);
112     LOG(DEBUG) << mName << __func__;
113     return RetCode::SUCCESS;
114 }
115 
threadLoop()116 void EffectThread::threadLoop() {
117     pthread_setname_np(pthread_self(), mName.substr(0, kMaxTaskNameLen - 1).c_str());
118     setpriority(PRIO_PROCESS, 0, mPriority);
119     while (true) {
120         /**
121          * wait for the EventFlag without lock, it's ok because the mEfGroup pointer will not change
122          * in the life cycle of workerThread (threadLoop).
123          */
124         uint32_t efState = 0;
125         mEfGroup->wait(kEventFlagNotEmpty, &efState);
126 
127         {
128             std::unique_lock l(mThreadMutex);
129             ::android::base::ScopedLockAssertion lock_assertion(mThreadMutex);
130             mCv.wait(l, [&]() REQUIRES(mThreadMutex) { return mExit || !mStop; });
131             if (mExit) {
132                 LOG(INFO) << __func__ << " EXIT!";
133                 return;
134             }
135             process_l();
136         }
137     }
138 }
139 
process_l()140 void EffectThread::process_l() {
141     RETURN_VALUE_IF(!mThreadContext, void(), "nullContext");
142 
143     auto statusMQ = mThreadContext->getStatusFmq();
144     auto inputMQ = mThreadContext->getInputDataFmq();
145     auto outputMQ = mThreadContext->getOutputDataFmq();
146     auto buffer = mThreadContext->getWorkBuffer();
147 
148     auto processSamples = inputMQ->availableToRead();
149     if (processSamples) {
150         inputMQ->read(buffer, processSamples);
151         IEffect::Status status = effectProcessImpl(buffer, buffer, processSamples);
152         outputMQ->write(buffer, status.fmqProduced);
153         statusMQ->writeBlocking(&status, 1);
154         LOG(VERBOSE) << mName << __func__ << ": done processing, effect consumed "
155                      << status.fmqConsumed << " produced " << status.fmqProduced;
156     }
157 }
158 
159 }  // namespace aidl::android::hardware::audio::effect
160