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