• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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