1 /* 2 * Copyright (C) 2024 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 19 #include <android/media/BnEffectClient.h> 20 #include <audio_utils/CommandThread.h> 21 22 namespace android::media { 23 24 class EffectClientAsyncProxy : public IEffectClient { 25 public: 26 27 /** 28 * Call this factory method to interpose a worker thread when a binder 29 * callback interface is invoked in-proc. 30 */ makeIfNeeded(const sp<IEffectClient> & effectClient)31 static sp<IEffectClient> makeIfNeeded(const sp<IEffectClient>& effectClient) { 32 if (isLocalBinder(effectClient)) { 33 return sp<EffectClientAsyncProxy>::make(effectClient); 34 } 35 return effectClient; 36 } 37 EffectClientAsyncProxy(const sp<IEffectClient> & effectClient)38 explicit EffectClientAsyncProxy(const sp<IEffectClient>& effectClient) 39 : mEffectClient(effectClient) {} 40 onAsBinder()41 ::android::IBinder* onAsBinder() override { 42 return nullptr; 43 } 44 controlStatusChanged(bool controlGranted)45 ::android::binder::Status controlStatusChanged(bool controlGranted) override { 46 getThread().add(__func__, [=, effectClient = mEffectClient]() { 47 effectClient->controlStatusChanged(controlGranted); 48 }); 49 return ::android::binder::Status::fromStatusT(::android::NO_ERROR); 50 } 51 enableStatusChanged(bool enabled)52 ::android::binder::Status enableStatusChanged(bool enabled) override { 53 getThread().add(__func__, [=, effectClient = mEffectClient]() { 54 effectClient->enableStatusChanged(enabled); 55 }); 56 return ::android::binder::Status::fromStatusT(::android::NO_ERROR); 57 } 58 commandExecuted(int32_t cmdCode,const::std::vector<uint8_t> & cmdData,const::std::vector<uint8_t> & replyData)59 ::android::binder::Status commandExecuted( 60 int32_t cmdCode, const ::std::vector<uint8_t>& cmdData, 61 const ::std::vector<uint8_t>& replyData) override { 62 getThread().add(__func__, [=, effectClient = mEffectClient]() { 63 effectClient->commandExecuted(cmdCode, cmdData, replyData); 64 }); 65 return ::android::binder::Status::fromStatusT(::android::NO_ERROR); 66 } 67 framesProcessed(int32_t frames)68 ::android::binder::Status framesProcessed(int32_t frames) override { 69 getThread().add(__func__, [=, effectClient = mEffectClient]() { 70 effectClient->framesProcessed(frames); 71 }); 72 return ::android::binder::Status::fromStatusT(::android::NO_ERROR); 73 } 74 75 /** 76 * Returns true if the binder interface is local (in-proc). 77 * 78 * Move to a binder helper class? 79 */ isLocalBinder(const sp<IInterface> & interface)80 static bool isLocalBinder(const sp<IInterface>& interface) { 81 const auto b = IInterface::asBinder(interface); 82 return b && b->localBinder(); 83 } 84 85 private: 86 const sp<IEffectClient> mEffectClient; 87 88 /** 89 * Returns the per-interface-descriptor CommandThread for in-proc binder transactions. 90 * 91 * Note: Remote RPC transactions to a given binder (kernel) node enter that node's 92 * async_todo list, which serializes all async operations to that binder node. 93 * Each transaction on the async_todo list must complete before the next one 94 * starts, even though there may be available threads in the process threadpool. 95 * 96 * For local transactions, we order all async requests entering 97 * the CommandThread. We do not maintain a threadpool, though a future implementation 98 * could use a shared ThreadPool. 99 * 100 * By using a static here, all in-proc binder interfaces made async with 101 * EffectClientAsyncProxy will get the same CommandThread. 102 * 103 * @return CommandThread to use. 104 */ getThread()105 static audio_utils::CommandThread& getThread() { 106 [[clang::no_destroy]] static audio_utils::CommandThread commandThread; 107 return commandThread; 108 } 109 }; // class EffectClientAsyncProxy 110 111 } // namespace android::media 112