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 #pragma once 18 #include <atomic> 19 #include <memory> 20 #include <string> 21 #include <thread> 22 23 #include <android-base/thread_annotations.h> 24 #include <fmq/EventFlag.h> 25 #include <system/thread_defs.h> 26 27 #include "effect-impl/EffectContext.h" 28 #include "effect-impl/EffectTypes.h" 29 30 namespace aidl::android::hardware::audio::effect { 31 32 class EffectThread { 33 public: 34 // default priority is same as HIDL: ANDROID_PRIORITY_URGENT_AUDIO 35 EffectThread(); 36 virtual ~EffectThread(); 37 38 // called by effect implementation. 39 RetCode createThread(std::shared_ptr<EffectContext> context, const std::string& name, 40 int priority = ANDROID_PRIORITY_URGENT_AUDIO); 41 RetCode destroyThread(); 42 RetCode startThread(); 43 RetCode stopThread(); 44 45 // Will call process() in a loop if the thread is running. 46 void threadLoop(); 47 48 /** 49 * @brief effectProcessImpl is running in worker thread which created in EffectThread. 50 * 51 * Effect implementation should think about concurrency in the implementation if necessary. 52 * Parameter setting usually implemented in context (derived from EffectContext), and some 53 * parameter maybe used in the processing, then effect implementation should consider using a 54 * mutex to protect these parameter. 55 * 56 * EffectThread will make sure effectProcessImpl only be called after startThread() successful 57 * and before stopThread() successful. 58 * 59 * effectProcessImpl implementation must not call any EffectThread interface, otherwise it will 60 * cause deadlock. 61 * 62 * @param in address of input float buffer. 63 * @param out address of output float buffer. 64 * @param samples number of samples to process. 65 * @return IEffect::Status 66 */ 67 virtual IEffect::Status effectProcessImpl(float* in, float* out, int samples) = 0; 68 69 /** 70 * process() call effectProcessImpl() for effect data processing, it is necessary for the 71 * processing to be called under Effect thread mutex mThreadMutex, to avoid the effect state 72 * change before/during data processing, and keep the thread and effect state consistent. 73 */ 74 virtual void process_l() REQUIRES(mThreadMutex); 75 76 private: 77 static constexpr int kMaxTaskNameLen = 15; 78 79 std::mutex mThreadMutex; 80 std::condition_variable mCv; 81 bool mStop GUARDED_BY(mThreadMutex) = true; 82 bool mExit GUARDED_BY(mThreadMutex) = false; 83 std::shared_ptr<EffectContext> mThreadContext GUARDED_BY(mThreadMutex); 84 85 struct EventFlagDeleter { operatorEventFlagDeleter86 void operator()(::android::hardware::EventFlag* flag) const { 87 if (flag) { 88 ::android::hardware::EventFlag::deleteEventFlag(&flag); 89 } 90 } 91 }; 92 std::unique_ptr<::android::hardware::EventFlag, EventFlagDeleter> mEfGroup; 93 std::thread mThread; 94 int mPriority; 95 std::string mName; 96 }; 97 } // namespace aidl::android::hardware::audio::effect 98