blob: 47e237be9c7a0bfeb2216640fd9b31e7b2b39623 [file] [log] [blame]
// Copyright 2020 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "FaceTracker.h"
#include <android-base/logging.h>
#include <android/binder_manager.h>
#include <utils/Log.h>
#include <memory>
#include <mutex>
#include <thread>
namespace android {
namespace automotive {
namespace computepipe {
using ::android::automotive::computepipe::example::FaceOutput;
namespace {
constexpr char kReigstryInterface[] = "router";
constexpr char kGraphName[] = "Face Tracker Graph";
} // namespace
/**
* RemoteState monitor
*/
PipeState RemoteState::GetCurrentState() {
std::unique_lock<std::mutex> lock(mStateLock);
mWait.wait(lock, [this]() { return hasChanged; });
hasChanged = false;
return mState;
}
void RemoteState::UpdateCurrentState(const PipeState& state) {
std::lock_guard<std::mutex> lock(mStateLock);
mState = state;
if (mState == PipeState::ERR_HALT) {
mTerminationCb(true, "Received error from runner");
} else if (mState == PipeState::DONE) {
mTerminationCb(false, "");
} else {
hasChanged = true;
mWait.notify_all();
}
}
RemoteState::RemoteState(std::function<void(bool, std::string)>& cb) : mTerminationCb(cb) {
}
/**
* StateCallback methods
*/
StateCallback::StateCallback(std::shared_ptr<RemoteState> s) : mStateTracker(s) {
}
ndk::ScopedAStatus StateCallback::handleState(PipeState state) {
mStateTracker->UpdateCurrentState(state);
return ndk::ScopedAStatus::ok();
}
/**
* FaceTracker methods
*/
ndk::ScopedAStatus FaceTracker::init(std::function<void(bool, std::string)>&& cb) {
auto termination = cb;
mRemoteState = std::make_shared<RemoteState>(termination);
std::string instanceName = std::string() + IPipeQuery::descriptor + "/" + kReigstryInterface;
ndk::SpAIBinder binder(AServiceManager_getService(instanceName.c_str()));
CHECK(binder.get());
std::shared_ptr<IPipeQuery> queryService = IPipeQuery::fromBinder(binder);
mClientInfo = ndk::SharedRefBase::make<ClientInfo>();
ndk::ScopedAStatus status = queryService->getPipeRunner(kGraphName, mClientInfo, &mPipeRunner);
if (!status.isOk()) {
LOG(ERROR) << "Failed to get handle to runner";
return status;
}
mStreamCallback = ndk::SharedRefBase::make<StreamCallback>();
mStateCallback = ndk::SharedRefBase::make<StateCallback>(mRemoteState);
return setupConfig();
}
ndk::ScopedAStatus FaceTracker::setupConfig() {
ndk::ScopedAStatus status = mPipeRunner->init(mStateCallback);
if (!status.isOk()) {
LOG(ERROR) << "Failed to init runner";
return status;
}
status = mPipeRunner->setPipeInputSource(0);
if (!status.isOk()) {
LOG(ERROR) << "Failed to set pipe input config";
return status;
}
status = mPipeRunner->setPipeOutputConfig(0, 10, mStreamCallback);
if (!status.isOk()) {
LOG(ERROR) << "Failed to set pipe output config";
return status;
}
status = mPipeRunner->applyPipeConfigs();
if (!status.isOk()) {
LOG(ERROR) << "Failed to set apply configs";
return status;
}
std::thread t(&FaceTracker::start, this);
t.detach();
return ndk::ScopedAStatus::ok();
}
void FaceTracker::start() {
PipeState state = mRemoteState->GetCurrentState();
CHECK(state == PipeState::CONFIG_DONE);
ndk::ScopedAStatus status = mPipeRunner->startPipe();
CHECK(status.isOk());
state = mRemoteState->GetCurrentState();
CHECK(state == PipeState::RUNNING);
}
void FaceTracker::stop() {
ndk::ScopedAStatus status = mPipeRunner->startPipe();
CHECK(status.isOk());
}
/**
* Stream Callback implementation
*/
ndk::ScopedAStatus StreamCallback::deliverPacket(const PacketDescriptor& in_packet) {
std::string output(in_packet.data.begin(), in_packet.data.end());
FaceOutput faceData;
faceData.ParseFromString(output);
BoundingBox currentBox = faceData.box();
if (!faceData.has_box()) {
mLastBox = BoundingBox();
return ndk::ScopedAStatus::ok();
}
if (!mLastBox.has_top_x()) {
mLastBox = currentBox;
return ndk::ScopedAStatus::ok();
}
if (currentBox.top_x() > mLastBox.top_x() + 1) {
LOG(ERROR) << "Face moving left";
} else if (currentBox.top_x() + 1 < mLastBox.top_x()) {
LOG(ERROR) << "Face moving right";
}
mLastBox = currentBox;
return ndk::ScopedAStatus::ok();
}
} // namespace computepipe
} // namespace automotive
} // namespace android