blob: b0e4ca3e4e202c0ba1a46417231c9c61cb3724cd [file] [log] [blame]
/*
* Copyright (C) 2021 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.
*/
#define LOG_TAG "Camera3DeviceInjectionMethods"
#define ATRACE_TAG ATRACE_TAG_CAMERA
//#define LOG_NDEBUG 0
#include <utils/Log.h>
#include <utils/Trace.h>
#include "common/CameraProviderManager.h"
#include "device3/Camera3Device.h"
namespace android {
Camera3Device::Camera3DeviceInjectionMethods::Camera3DeviceInjectionMethods(
wp<Camera3Device> parent)
: mParent(parent) {
ALOGV("%s: Created injection camera methods", __FUNCTION__);
}
Camera3Device::Camera3DeviceInjectionMethods::~Camera3DeviceInjectionMethods() {
ALOGV("%s: Removed injection camera methods", __FUNCTION__);
injectionDisconnectImpl();
}
status_t Camera3Device::Camera3DeviceInjectionMethods::injectCamera(
camera3::camera_stream_configuration& injectionConfig,
const std::vector<uint32_t>& injectionBufferSizes) {
status_t res = NO_ERROR;
if (mInjectedCamHalInterface == nullptr) {
ALOGE("%s: mInjectedCamHalInterface does not exist!", __FUNCTION__);
return DEAD_OBJECT;
}
sp<Camera3Device> parent = mParent.promote();
if (parent == nullptr) {
ALOGE("%s: parent does not exist!", __FUNCTION__);
return INVALID_OPERATION;
}
nsecs_t maxExpectedDuration = parent->getExpectedInFlightDuration();
bool wasActive = false;
if (parent->mStatus == STATUS_ACTIVE) {
ALOGV("%s: Let the device be IDLE and the request thread is paused",
__FUNCTION__);
res = parent->internalPauseAndWaitLocked(maxExpectedDuration,
/*requestThreadInvocation*/false);
if (res != OK) {
ALOGE("%s: Can't pause captures to inject camera!", __FUNCTION__);
return res;
}
wasActive = true;
}
ALOGV("%s: Injection camera: replaceHalInterface", __FUNCTION__);
res = replaceHalInterface(mInjectedCamHalInterface, true);
if (res != OK) {
ALOGE("%s: Failed to replace the new HalInterface!", __FUNCTION__);
injectionDisconnectImpl();
return res;
}
res = parent->mRequestThread->setHalInterface(mInjectedCamHalInterface);
if (res != OK) {
ALOGE("%s: Failed to set new HalInterface in RequestThread!", __FUNCTION__);
replaceHalInterface(mBackupHalInterface, false);
injectionDisconnectImpl();
return res;
}
parent->mNeedConfig = true;
res = injectionConfigureStreams(injectionConfig, injectionBufferSizes);
parent->mNeedConfig = false;
if (res != OK) {
ALOGE("Can't injectionConfigureStreams device for streams: %d: %s "
"(%d)", parent->mNextStreamId, strerror(-res), res);
replaceHalInterface(mBackupHalInterface, false);
injectionDisconnectImpl();
return res;
}
if (wasActive) {
ALOGV("%s: Restarting activity to inject camera", __FUNCTION__);
// Reuse current operating mode and session parameters for new stream
// config.
parent->internalResumeLocked();
}
return OK;
}
status_t Camera3Device::Camera3DeviceInjectionMethods::stopInjection() {
status_t res = NO_ERROR;
sp<Camera3Device> parent = mParent.promote();
if (parent == nullptr) {
ALOGE("%s: parent does not exist!", __FUNCTION__);
return DEAD_OBJECT;
}
nsecs_t maxExpectedDuration = parent->getExpectedInFlightDuration();
bool wasActive = false;
if (parent->mStatus == STATUS_ACTIVE) {
ALOGV("%s: Let the device be IDLE and the request thread is paused",
__FUNCTION__);
res = parent->internalPauseAndWaitLocked(maxExpectedDuration,
/*requestThreadInvocation*/false);
if (res != OK) {
ALOGE("%s: Can't pause captures to stop injection!", __FUNCTION__);
return res;
}
wasActive = true;
}
res = replaceHalInterface(mBackupHalInterface, false);
if (res != OK) {
ALOGE("%s: Failed to restore the backup HalInterface!", __FUNCTION__);
injectionDisconnectImpl();
return res;
}
injectionDisconnectImpl();
if (wasActive) {
ALOGV("%s: Restarting activity to stop injection", __FUNCTION__);
// Reuse current operating mode and session parameters for new stream
// config.
parent->internalResumeLocked();
}
return OK;
}
bool Camera3Device::Camera3DeviceInjectionMethods::isInjecting() {
if (mInjectedCamHalInterface == nullptr) {
return false;
} else {
return true;
}
}
bool Camera3Device::Camera3DeviceInjectionMethods::isStreamConfigCompleteButNotInjected() {
return mIsStreamConfigCompleteButNotInjected;
}
const std::string& Camera3Device::Camera3DeviceInjectionMethods::getInjectedCamId()
const {
return mInjectedCamId;
}
void Camera3Device::Camera3DeviceInjectionMethods::getInjectionConfig(
/*out*/ camera3::camera_stream_configuration* injectionConfig,
/*out*/ std::vector<uint32_t>* injectionBufferSizes) {
if (injectionConfig == nullptr || injectionBufferSizes == nullptr) {
ALOGE("%s: Injection configuration arguments must not be null!", __FUNCTION__);
return;
}
*injectionConfig = mInjectionConfig;
*injectionBufferSizes = mInjectionBufferSizes;
}
void Camera3Device::Camera3DeviceInjectionMethods::storeInjectionConfig(
const camera3::camera_stream_configuration& injectionConfig,
const std::vector<uint32_t>& injectionBufferSizes) {
mIsStreamConfigCompleteButNotInjected = true;
mInjectionConfig = injectionConfig;
mInjectionStreams.clear();
for (size_t i = 0; i < injectionConfig.num_streams; i++) {
mInjectionStreams.push_back(injectionConfig.streams[i]);
}
mInjectionConfig.streams = mInjectionStreams.editArray();
mInjectionBufferSizes = injectionBufferSizes;
}
status_t Camera3Device::Camera3DeviceInjectionMethods::injectionConfigureStreams(
camera3::camera_stream_configuration& injectionConfig,
const std::vector<uint32_t>& injectionBufferSizes) {
ATRACE_CALL();
status_t res = NO_ERROR;
sp<Camera3Device> parent = mParent.promote();
if (parent == nullptr) {
ALOGE("%s: parent does not exist!", __FUNCTION__);
return INVALID_OPERATION;
}
if (parent->mOperatingMode < 0) {
ALOGE("Invalid operating mode: %d", parent->mOperatingMode);
return BAD_VALUE;
}
// Start configuring the streams
ALOGV("%s: Injection camera %s: Starting stream configuration", __FUNCTION__,
mInjectedCamId.c_str());
parent->mPreparerThread->pause();
// Do the HAL configuration; will potentially touch stream
// max_buffers, usage, and priv fields, as well as data_space and format
// fields for IMPLEMENTATION_DEFINED formats.
const camera_metadata_t* sessionBuffer = parent->mSessionParams.getAndLock();
res = mInjectedCamHalInterface->configureInjectedStreams(
sessionBuffer, &injectionConfig, injectionBufferSizes,
parent->mDeviceInfo);
parent->mSessionParams.unlock(sessionBuffer);
if (res == BAD_VALUE) {
// HAL rejected this set of streams as unsupported, clean up config
// attempt and return to unconfigured state
ALOGE("Set of requested outputs not supported by HAL");
parent->cancelStreamsConfigurationLocked();
return BAD_VALUE;
} else if (res != OK) {
// Some other kind of error from configure_streams - this is not
// expected
ALOGE("Unable to configure streams with HAL: %s (%d)", strerror(-res),
res);
return res;
}
for (size_t i = 0; i < parent->mOutputStreams.size(); i++) {
sp<camera3::Camera3OutputStreamInterface> outputStream =
parent->mOutputStreams[i];
mInjectedCamHalInterface->onStreamReConfigured(outputStream->getId());
}
// Request thread needs to know to avoid using repeat-last-settings protocol
// across configure_streams() calls
parent->mRequestThread->configurationComplete(
parent->mIsConstrainedHighSpeedConfiguration, parent->mSessionParams,
parent->mGroupIdPhysicalCameraMap);
parent->internalUpdateStatusLocked(STATUS_CONFIGURED);
ALOGV("%s: Injection camera %s: Stream configuration complete", __FUNCTION__,
mInjectedCamId.c_str());
auto rc = parent->mPreparerThread->resume();
if (rc != OK) {
ALOGE("%s: Injection camera %s: Preparer thread failed to resume!",
__FUNCTION__, mInjectedCamId.c_str());
return rc;
}
return OK;
}
void Camera3Device::Camera3DeviceInjectionMethods::injectionDisconnectImpl() {
ATRACE_CALL();
ALOGI("%s: Injection camera disconnect", __FUNCTION__);
mIsStreamConfigCompleteButNotInjected = false;
mInjectionStreams.clear();
mInjectionConfig.streams = nullptr;
mBackupHalInterface = nullptr;
HalInterface* interface = nullptr;
{
Mutex::Autolock lock(mInjectionLock);
if (mInjectedCamHalInterface != nullptr) {
interface = mInjectedCamHalInterface.get();
// Call close without internal mutex held, as the HAL close may need
// to wait on assorted callbacks,etc, to complete before it can
// return.
}
}
if (interface != nullptr) {
interface->close();
}
{
Mutex::Autolock lock(mInjectionLock);
if (mInjectedCamHalInterface != nullptr) {
mInjectedCamHalInterface->clear();
mInjectedCamHalInterface = nullptr;
}
}
}
}; // namespace android