• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "FaceTracker.h"
16 
17 #include <android-base/logging.h>
18 #include <android/binder_manager.h>
19 #include <utils/Log.h>
20 
21 #include <memory>
22 #include <mutex>
23 #include <thread>
24 
25 namespace android {
26 namespace automotive {
27 namespace computepipe {
28 
29 using ::android::automotive::computepipe::example::FaceOutput;
30 namespace {
31 constexpr char kReigstryInterface[] = "router";
32 constexpr char kGraphName[] = "Face Tracker Graph";
33 }  // namespace
34 
35 /**
36  * RemoteState monitor
37  */
GetCurrentState()38 PipeState RemoteState::GetCurrentState() {
39     std::unique_lock<std::mutex> lock(mStateLock);
40     mWait.wait(lock, [this]() { return hasChanged; });
41     hasChanged = false;
42     return mState;
43 }
44 
UpdateCurrentState(const PipeState & state)45 void RemoteState::UpdateCurrentState(const PipeState& state) {
46     std::lock_guard<std::mutex> lock(mStateLock);
47     mState = state;
48     if (mState == PipeState::ERR_HALT) {
49         mTerminationCb(true, "Received error from runner");
50     } else if (mState == PipeState::DONE) {
51         mTerminationCb(false, "");
52     } else {
53         hasChanged = true;
54         mWait.notify_all();
55     }
56 }
57 
RemoteState(std::function<void (bool,std::string)> & cb)58 RemoteState::RemoteState(std::function<void(bool, std::string)>& cb) : mTerminationCb(cb) {
59 }
60 
61 /**
62  * StateCallback methods
63  */
StateCallback(std::shared_ptr<RemoteState> s)64 StateCallback::StateCallback(std::shared_ptr<RemoteState> s) : mStateTracker(s) {
65 }
66 
handleState(PipeState state)67 ndk::ScopedAStatus StateCallback::handleState(PipeState state) {
68     mStateTracker->UpdateCurrentState(state);
69     return ndk::ScopedAStatus::ok();
70 }
71 
72 /**
73  * FaceTracker methods
74  */
init(std::function<void (bool,std::string)> && cb)75 ndk::ScopedAStatus FaceTracker::init(std::function<void(bool, std::string)>&& cb) {
76     auto termination = cb;
77     mRemoteState = std::make_shared<RemoteState>(termination);
78     std::string instanceName = std::string() + IPipeQuery::descriptor + "/" + kReigstryInterface;
79 
80     ndk::SpAIBinder binder(AServiceManager_getService(instanceName.c_str()));
81     CHECK(binder.get());
82 
83     std::shared_ptr<IPipeQuery> queryService = IPipeQuery::fromBinder(binder);
84     mClientInfo = ndk::SharedRefBase::make<ClientInfo>();
85     ndk::ScopedAStatus status = queryService->getPipeRunner(kGraphName, mClientInfo, &mPipeRunner);
86     if (!status.isOk()) {
87         LOG(ERROR) << "Failed to get handle to runner";
88         return status;
89     }
90     mStreamCallback = ndk::SharedRefBase::make<StreamCallback>();
91     mStateCallback = ndk::SharedRefBase::make<StateCallback>(mRemoteState);
92     return setupConfig();
93 }
94 
setupConfig()95 ndk::ScopedAStatus FaceTracker::setupConfig() {
96     ndk::ScopedAStatus status = mPipeRunner->init(mStateCallback);
97     if (!status.isOk()) {
98         LOG(ERROR) << "Failed to init runner";
99         return status;
100     }
101     status = mPipeRunner->setPipeInputSource(0);
102     if (!status.isOk()) {
103         LOG(ERROR) << "Failed to set pipe input config";
104         return status;
105     }
106     status = mPipeRunner->setPipeOutputConfig(0, 10, mStreamCallback);
107     if (!status.isOk()) {
108         LOG(ERROR) << "Failed to set pipe output config";
109         return status;
110     }
111     status = mPipeRunner->applyPipeConfigs();
112     if (!status.isOk()) {
113         LOG(ERROR) << "Failed to set apply configs";
114         return status;
115     }
116     std::thread t(&FaceTracker::start, this);
117     t.detach();
118     return ndk::ScopedAStatus::ok();
119 }
120 
start()121 void FaceTracker::start() {
122     PipeState state = mRemoteState->GetCurrentState();
123     CHECK(state == PipeState::CONFIG_DONE);
124     ndk::ScopedAStatus status = mPipeRunner->startPipe();
125     CHECK(status.isOk());
126     state = mRemoteState->GetCurrentState();
127     CHECK(state == PipeState::RUNNING);
128 }
129 
stop()130 void FaceTracker::stop() {
131     ndk::ScopedAStatus status = mPipeRunner->startPipe();
132     CHECK(status.isOk());
133 }
134 
135 /**
136  * Stream Callback implementation
137  */
138 
deliverPacket(const PacketDescriptor & in_packet)139 ndk::ScopedAStatus StreamCallback::deliverPacket(const PacketDescriptor& in_packet) {
140     std::string output(in_packet.data.begin(), in_packet.data.end());
141 
142     FaceOutput faceData;
143     faceData.ParseFromString(output);
144 
145     BoundingBox currentBox = faceData.box();
146 
147     if (!faceData.has_box()) {
148         mLastBox = BoundingBox();
149         return ndk::ScopedAStatus::ok();
150     }
151 
152     if (!mLastBox.has_top_x()) {
153         mLastBox = currentBox;
154         return ndk::ScopedAStatus::ok();
155     }
156 
157     if (currentBox.top_x() > mLastBox.top_x() + 1) {
158         LOG(ERROR) << "Face moving left";
159     } else if (currentBox.top_x() + 1 < mLastBox.top_x()) {
160         LOG(ERROR) << "Face moving right";
161     }
162     mLastBox = currentBox;
163     return ndk::ScopedAStatus::ok();
164 }
165 
166 }  // namespace computepipe
167 }  // namespace automotive
168 }  // namespace android
169