You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
596 lines
21 KiB
596 lines
21 KiB
/*
|
|
* Copyright (C) 2019 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_NDEBUG 0
|
|
#define LOG_TAG "ECOSession"
|
|
//#define DEBUG_ECO_SESSION
|
|
#include "eco/ECOSession.h"
|
|
|
|
#include <binder/BinderService.h>
|
|
#include <cutils/atomic.h>
|
|
#include <inttypes.h>
|
|
#include <pthread.h>
|
|
#include <stdio.h>
|
|
#include <sys/types.h>
|
|
#include <utils/Log.h>
|
|
|
|
#include <algorithm>
|
|
#include <climits>
|
|
#include <cstring>
|
|
#include <ctime>
|
|
#include <string>
|
|
|
|
#include "eco/ECODataKey.h"
|
|
#include "eco/ECODebug.h"
|
|
|
|
namespace android {
|
|
namespace media {
|
|
namespace eco {
|
|
|
|
using android::binder::Status;
|
|
using android::sp;
|
|
|
|
#define RETURN_IF_ERROR(expr) \
|
|
{ \
|
|
status_t _errorCode = (expr); \
|
|
if (_errorCode != true) { \
|
|
return _errorCode; \
|
|
} \
|
|
}
|
|
|
|
// static
|
|
sp<ECOSession> ECOSession::createECOSession(int32_t width, int32_t height, bool isCameraRecording) {
|
|
// Only support up to 1080P.
|
|
// TODO: Support the same resolution as in EAF.
|
|
if (width <= 0 || height <= 0 || width > 5120 || height > 5120 ||
|
|
width > 1920 * 1080 / height) {
|
|
ECOLOGE("Failed to create ECOSession with w: %d, h: %d, isCameraRecording: %d", width,
|
|
height, isCameraRecording);
|
|
return nullptr;
|
|
}
|
|
return new ECOSession(width, height, isCameraRecording);
|
|
}
|
|
|
|
ECOSession::ECOSession(int32_t width, int32_t height, bool isCameraRecording)
|
|
: BnECOSession(),
|
|
mStopThread(false),
|
|
mLastReportedQp(0),
|
|
mListener(nullptr),
|
|
mProvider(nullptr),
|
|
mWidth(width),
|
|
mHeight(height),
|
|
mIsCameraRecording(isCameraRecording) {
|
|
ECOLOGI("ECOSession created with w: %d, h: %d, isCameraRecording: %d", mWidth, mHeight,
|
|
mIsCameraRecording);
|
|
mThread = std::thread(startThread, this);
|
|
|
|
// Read the debug properies.
|
|
mLogStats = property_get_bool(kDebugLogStats, false);
|
|
mLogStatsEntries = mLogStats ? property_get_int32(kDebugLogStatsSize, 0) : 0;
|
|
|
|
mLogInfo = property_get_bool(kDebugLogStats, false);
|
|
mLogInfoEntries = mLogInfo ? property_get_int32(kDebugLogInfosSize, 0) : 0;
|
|
|
|
ECOLOGI("ECOSession debug settings: logStats: %s, entries: %d, logInfo: %s entries: %d",
|
|
mLogStats ? "true" : "false", mLogStatsEntries, mLogInfo ? "true" : "false",
|
|
mLogInfoEntries);
|
|
}
|
|
|
|
ECOSession::~ECOSession() {
|
|
mStopThread = true;
|
|
|
|
mWorkerWaitCV.notify_all();
|
|
if (mThread.joinable()) {
|
|
ECOLOGD("ECOSession: join the thread");
|
|
mThread.join();
|
|
}
|
|
ECOLOGI("ECOSession destroyed with w: %d, h: %d, isCameraRecording: %d", mWidth, mHeight,
|
|
mIsCameraRecording);
|
|
}
|
|
|
|
// static
|
|
void ECOSession::startThread(ECOSession* session) {
|
|
session->run();
|
|
}
|
|
|
|
void ECOSession::run() {
|
|
ECOLOGD("ECOSession: starting main thread");
|
|
|
|
while (!mStopThread) {
|
|
std::unique_lock<std::mutex> runLock(mStatsQueueLock);
|
|
|
|
mWorkerWaitCV.wait(runLock, [this] {
|
|
return mStopThread == true || !mStatsQueue.empty() || mNewListenerAdded;
|
|
});
|
|
|
|
if (mStopThread) return;
|
|
|
|
std::scoped_lock<std::mutex> lock(mSessionLock);
|
|
if (mNewListenerAdded) {
|
|
// Check if there is any session info available.
|
|
ECOData sessionInfo = generateLatestSessionInfoEcoData();
|
|
if (!sessionInfo.isEmpty()) {
|
|
Status status = mListener->onNewInfo(sessionInfo);
|
|
if (!status.isOk()) {
|
|
ECOLOGE("%s: Failed to publish info: %s due to binder error", __FUNCTION__,
|
|
sessionInfo.debugString().c_str());
|
|
// Remove the listener. The lock has been acquired outside this function.
|
|
mListener = nullptr;
|
|
}
|
|
}
|
|
mNewListenerAdded = false;
|
|
}
|
|
|
|
if (!mStatsQueue.empty()) {
|
|
ECOData stats = mStatsQueue.front();
|
|
mStatsQueue.pop_front();
|
|
processStats(stats); // TODO: Handle the error from processStats
|
|
}
|
|
}
|
|
|
|
ECOLOGD("ECOSession: exiting main thread");
|
|
}
|
|
|
|
bool ECOSession::processStats(const ECOData& stats) {
|
|
ECOLOGV("%s: receive stats: %s", __FUNCTION__, stats.debugString().c_str());
|
|
|
|
if (stats.getDataType() != ECOData::DATA_TYPE_STATS) {
|
|
ECOLOGE("Invalid stats. ECOData with type: %s", stats.getDataTypeString().c_str());
|
|
return false;
|
|
}
|
|
|
|
// Get the type of the stats.
|
|
std::string statsType;
|
|
if (stats.findString(KEY_STATS_TYPE, &statsType) != ECODataStatus::OK) {
|
|
ECOLOGE("Invalid stats ECOData without statsType");
|
|
return false;
|
|
}
|
|
|
|
if (statsType.compare(VALUE_STATS_TYPE_SESSION) == 0) {
|
|
processSessionStats(stats);
|
|
} else if (statsType.compare(VALUE_STATS_TYPE_FRAME) == 0) {
|
|
processFrameStats(stats);
|
|
} else {
|
|
ECOLOGE("processStats:: Failed to process stats as ECOData contains unknown stats type");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void ECOSession::processSessionStats(const ECOData& stats) {
|
|
ECOLOGV("processSessionStats");
|
|
|
|
ECOData info(ECOData::DATA_TYPE_INFO, systemTime(SYSTEM_TIME_BOOTTIME));
|
|
info.setString(KEY_INFO_TYPE, VALUE_INFO_TYPE_SESSION);
|
|
|
|
ECODataKeyValueIterator iter(stats);
|
|
while (iter.hasNext()) {
|
|
ECOData::ECODataKeyValuePair entry = iter.next();
|
|
const std::string& key = entry.first;
|
|
const ECOData::ECODataValueType value = entry.second;
|
|
ECOLOGV("Processing key: %s", key.c_str());
|
|
if (!key.compare(KEY_STATS_TYPE)) {
|
|
// Skip the key KEY_STATS_TYPE as that has been parsed already.
|
|
continue;
|
|
} else if (!key.compare(ENCODER_TYPE)) {
|
|
mCodecType = std::get<int32_t>(value);
|
|
ECOLOGV("codec type is %d", mCodecType);
|
|
} else if (!key.compare(ENCODER_PROFILE)) {
|
|
mCodecProfile = std::get<int32_t>(value);
|
|
ECOLOGV("codec profile is %d", mCodecProfile);
|
|
} else if (!key.compare(ENCODER_LEVEL)) {
|
|
mCodecLevel = std::get<int32_t>(value);
|
|
ECOLOGV("codec level is %d", mCodecLevel);
|
|
} else if (!key.compare(ENCODER_TARGET_BITRATE_BPS)) {
|
|
mTargetBitrateBps = std::get<int32_t>(value);
|
|
ECOLOGV("codec target bitrate is %d", mTargetBitrateBps);
|
|
} else if (!key.compare(ENCODER_KFI_FRAMES)) {
|
|
mKeyFrameIntervalFrames = std::get<int32_t>(value);
|
|
ECOLOGV("codec kfi is %d", mKeyFrameIntervalFrames);
|
|
} else if (!key.compare(ENCODER_FRAMERATE_FPS)) {
|
|
mFramerateFps = std::get<float>(value);
|
|
ECOLOGV("codec framerate is %f", mFramerateFps);
|
|
} else if (!key.compare(ENCODER_INPUT_WIDTH)) {
|
|
int32_t width = std::get<int32_t>(value);
|
|
if (width != mWidth) {
|
|
ECOLOGW("Codec width: %d, expected: %d", width, mWidth);
|
|
}
|
|
ECOLOGV("codec input width is %d", width);
|
|
} else if (!key.compare(ENCODER_INPUT_HEIGHT)) {
|
|
int32_t height = std::get<int32_t>(value);
|
|
if (height != mHeight) {
|
|
ECOLOGW("Codec height: %d, expected: %d", height, mHeight);
|
|
}
|
|
ECOLOGV("codec input height is %d", height);
|
|
} else if (!key.compare(ENCODER_OUTPUT_WIDTH)) {
|
|
mOutputWidth = std::get<int32_t>(value);
|
|
if (mOutputWidth != mWidth) {
|
|
ECOLOGW("Codec output width: %d, expected: %d", mOutputWidth, mWidth);
|
|
}
|
|
ECOLOGV("codec output width is %d", mOutputWidth);
|
|
} else if (!key.compare(ENCODER_OUTPUT_HEIGHT)) {
|
|
mOutputHeight = std::get<int32_t>(value);
|
|
if (mOutputHeight != mHeight) {
|
|
ECOLOGW("Codec output height: %d, expected: %d", mOutputHeight, mHeight);
|
|
}
|
|
ECOLOGV("codec output height is %d", mOutputHeight);
|
|
} else {
|
|
ECOLOGW("Unknown session stats key %s from provider.", key.c_str());
|
|
continue;
|
|
}
|
|
info.set(key, value);
|
|
}
|
|
|
|
if (mListener != nullptr) {
|
|
Status status = mListener->onNewInfo(info);
|
|
if (!status.isOk()) {
|
|
ECOLOGE("%s: Failed to publish info: %s due to binder error", __FUNCTION__,
|
|
info.debugString().c_str());
|
|
// Remove the listener. The lock has been acquired outside this function.
|
|
mListener = nullptr;
|
|
}
|
|
}
|
|
}
|
|
|
|
ECOData ECOSession::generateLatestSessionInfoEcoData() {
|
|
bool hasInfo = false;
|
|
|
|
ECOData info(ECOData::DATA_TYPE_INFO, systemTime(SYSTEM_TIME_BOOTTIME));
|
|
|
|
if (mOutputWidth != -1) {
|
|
info.setInt32(ENCODER_OUTPUT_WIDTH, mOutputWidth);
|
|
hasInfo = true;
|
|
}
|
|
|
|
if (mOutputHeight != -1) {
|
|
info.setInt32(ENCODER_OUTPUT_HEIGHT, mOutputHeight);
|
|
hasInfo = true;
|
|
}
|
|
|
|
if (mCodecType != -1) {
|
|
info.setInt32(ENCODER_TYPE, mCodecType);
|
|
hasInfo = true;
|
|
}
|
|
|
|
if (mCodecProfile != -1) {
|
|
info.setInt32(ENCODER_PROFILE, mCodecProfile);
|
|
hasInfo = true;
|
|
}
|
|
|
|
if (mCodecLevel != -1) {
|
|
info.setInt32(ENCODER_LEVEL, mCodecLevel);
|
|
hasInfo = true;
|
|
}
|
|
|
|
if (mTargetBitrateBps != -1) {
|
|
info.setInt32(ENCODER_TARGET_BITRATE_BPS, mTargetBitrateBps);
|
|
hasInfo = true;
|
|
}
|
|
|
|
if (mKeyFrameIntervalFrames != -1) {
|
|
info.setInt32(ENCODER_KFI_FRAMES, mKeyFrameIntervalFrames);
|
|
hasInfo = true;
|
|
}
|
|
|
|
if (mFramerateFps > 0) {
|
|
info.setFloat(ENCODER_FRAMERATE_FPS, mFramerateFps);
|
|
hasInfo = true;
|
|
}
|
|
|
|
if (hasInfo) {
|
|
info.setString(KEY_INFO_TYPE, VALUE_INFO_TYPE_SESSION);
|
|
}
|
|
return info;
|
|
}
|
|
|
|
void ECOSession::processFrameStats(const ECOData& stats) {
|
|
ECOLOGD("processFrameStats");
|
|
|
|
bool needToNotifyListener = false;
|
|
ECOData info(ECOData::DATA_TYPE_INFO, systemTime(SYSTEM_TIME_BOOTTIME));
|
|
info.setString(KEY_INFO_TYPE, VALUE_INFO_TYPE_FRAME);
|
|
|
|
ECODataKeyValueIterator iter(stats);
|
|
while (iter.hasNext()) {
|
|
ECOData::ECODataKeyValuePair entry = iter.next();
|
|
const std::string& key = entry.first;
|
|
const ECOData::ECODataValueType value = entry.second;
|
|
ECOLOGD("Processing %s key", key.c_str());
|
|
|
|
if (!key.compare(KEY_STATS_TYPE)) {
|
|
// Skip the key KEY_STATS_TYPE as that has been parsed already.
|
|
continue;
|
|
} else if (!key.compare(FRAME_NUM) || !key.compare(FRAME_PTS_US) ||
|
|
!key.compare(FRAME_TYPE) || !key.compare(FRAME_SIZE_BYTES) ||
|
|
!key.compare(ENCODER_ACTUAL_BITRATE_BPS) ||
|
|
!key.compare(ENCODER_FRAMERATE_FPS)) {
|
|
// Only process the keys that are supported by ECOService 1.0.
|
|
info.set(key, value);
|
|
} else if (!key.compare(FRAME_AVG_QP)) {
|
|
// Check the qp to see if need to notify the listener.
|
|
const int32_t currAverageQp = std::get<int32_t>(value);
|
|
|
|
// Check if the delta between current QP and last reported QP is larger than the
|
|
// threshold specified by the listener.
|
|
const bool largeQPChangeDetected =
|
|
abs(currAverageQp - mLastReportedQp) > mListenerQpCondition.mQpChangeThreshold;
|
|
|
|
// Check if the qp is going from below threshold to beyond threshold.
|
|
const bool exceedQpBlockinessThreshold =
|
|
(mLastReportedQp <= mListenerQpCondition.mQpBlocknessThreshold &&
|
|
currAverageQp > mListenerQpCondition.mQpBlocknessThreshold);
|
|
|
|
// Check if the qp is going from beyond threshold to below threshold.
|
|
const bool fallBelowQpBlockinessThreshold =
|
|
(mLastReportedQp > mListenerQpCondition.mQpBlocknessThreshold &&
|
|
currAverageQp <= mListenerQpCondition.mQpBlocknessThreshold);
|
|
|
|
// Notify the listener if any of the above three conditions met.
|
|
if (largeQPChangeDetected || exceedQpBlockinessThreshold ||
|
|
fallBelowQpBlockinessThreshold) {
|
|
mLastReportedQp = currAverageQp;
|
|
needToNotifyListener = true;
|
|
}
|
|
|
|
info.set(key, value);
|
|
} else {
|
|
ECOLOGW("Unknown frame stats key %s from provider.", key.c_str());
|
|
}
|
|
}
|
|
|
|
if (needToNotifyListener && mListener != nullptr) {
|
|
Status status = mListener->onNewInfo(info);
|
|
if (!status.isOk()) {
|
|
ECOLOGE("%s: Failed to publish info: %s due to binder error", __FUNCTION__,
|
|
info.debugString().c_str());
|
|
// Remove the listener. The lock has been acquired outside this function.
|
|
mListener = nullptr;
|
|
}
|
|
}
|
|
}
|
|
|
|
Status ECOSession::getIsCameraRecording(bool* _aidl_return) {
|
|
std::scoped_lock<std::mutex> lock(mSessionLock);
|
|
*_aidl_return = mIsCameraRecording;
|
|
return binder::Status::ok();
|
|
}
|
|
|
|
Status ECOSession::addStatsProvider(
|
|
const sp<::android::media::eco::IECOServiceStatsProvider>& provider,
|
|
const ::android::media::eco::ECOData& config, bool* status) {
|
|
::android::String16 name;
|
|
Status result = provider->getName(&name);
|
|
if (!result.isOk()) {
|
|
// This binder transaction failure may due to permission issue.
|
|
*status = false;
|
|
ALOGE("Failed to get provider name");
|
|
return STATUS_ERROR(ERROR_PERMISSION_DENIED, "Failed to get provider name");
|
|
}
|
|
|
|
ECOLOGV("Try to add stats provider name: %s uid: %d pid %d", ::android::String8(name).string(),
|
|
IPCThreadState::self()->getCallingUid(), IPCThreadState::self()->getCallingPid());
|
|
|
|
if (provider == nullptr) {
|
|
ECOLOGE("%s: provider must not be null", __FUNCTION__);
|
|
*status = false;
|
|
return STATUS_ERROR(ERROR_ILLEGAL_ARGUMENT, "Null provider given to addStatsProvider");
|
|
}
|
|
|
|
std::scoped_lock<std::mutex> lock(mSessionLock);
|
|
|
|
if (mProvider != nullptr) {
|
|
::android::String16 name;
|
|
mProvider->getName(&name);
|
|
String8 errorMsg = String8::format(
|
|
"ECOService 1.0 only supports one stats provider, current provider: %s",
|
|
::android::String8(name).string());
|
|
ECOLOGE("%s", errorMsg.string());
|
|
*status = false;
|
|
return STATUS_ERROR(ERROR_ALREADY_EXISTS, errorMsg.string());
|
|
}
|
|
|
|
// TODO: Handle the provider config.
|
|
if (config.getDataType() != ECOData::DATA_TYPE_STATS_PROVIDER_CONFIG) {
|
|
ECOLOGE("Provider config is invalid");
|
|
*status = false;
|
|
return STATUS_ERROR(ERROR_ILLEGAL_ARGUMENT, "Provider config is invalid");
|
|
}
|
|
|
|
mProvider = provider;
|
|
mProviderName = name;
|
|
*status = true;
|
|
return binder::Status::ok();
|
|
}
|
|
|
|
Status ECOSession::removeStatsProvider(
|
|
const sp<::android::media::eco::IECOServiceStatsProvider>& provider, bool* status) {
|
|
std::scoped_lock<std::mutex> lock(mSessionLock);
|
|
// Check if the provider is the same as current provider for the session.
|
|
if (IInterface::asBinder(provider) != IInterface::asBinder(mProvider)) {
|
|
*status = false;
|
|
ECOLOGE("Failed to remove provider");
|
|
return STATUS_ERROR(ERROR_ILLEGAL_ARGUMENT, "Provider does not match");
|
|
}
|
|
|
|
mProvider = nullptr;
|
|
*status = true;
|
|
return binder::Status::ok();
|
|
}
|
|
|
|
Status ECOSession::addInfoListener(
|
|
const sp<::android::media::eco::IECOServiceInfoListener>& listener,
|
|
const ::android::media::eco::ECOData& config, bool* status) {
|
|
ALOGV("%s: Add listener %p", __FUNCTION__, listener.get());
|
|
std::scoped_lock<std::mutex> lock(mSessionLock);
|
|
|
|
::android::String16 name;
|
|
Status result = listener->getName(&name);
|
|
if (!result.isOk()) {
|
|
// This binder transaction failure may due to permission issue.
|
|
*status = false;
|
|
ALOGE("Failed to get listener name");
|
|
return STATUS_ERROR(ERROR_PERMISSION_DENIED, "Failed to get listener name");
|
|
}
|
|
|
|
if (mListener != nullptr) {
|
|
ECOLOGE("ECOService 1.0 only supports one listener");
|
|
*status = false;
|
|
return STATUS_ERROR(ERROR_ALREADY_EXISTS, "ECOService 1.0 only supports one listener");
|
|
}
|
|
|
|
if (listener == nullptr) {
|
|
ECOLOGE("%s: listener must not be null", __FUNCTION__);
|
|
*status = false;
|
|
return STATUS_ERROR(ERROR_ILLEGAL_ARGUMENT, "Null listener given to addInfoListener");
|
|
}
|
|
|
|
if (config.getDataType() != ECOData::DATA_TYPE_INFO_LISTENER_CONFIG) {
|
|
*status = false;
|
|
ECOLOGE("%s: listener config is invalid", __FUNCTION__);
|
|
return STATUS_ERROR(ERROR_ILLEGAL_ARGUMENT, "listener config is invalid");
|
|
}
|
|
|
|
if (config.isEmpty()) {
|
|
*status = false;
|
|
ECOLOGE("Listener must provide listening criterion");
|
|
return STATUS_ERROR(ERROR_ILLEGAL_ARGUMENT, "listener config is empty");
|
|
}
|
|
|
|
// For ECOService 1.0, listener must specify the two threshold in order to receive info.
|
|
if (config.findInt32(KEY_LISTENER_QP_BLOCKINESS_THRESHOLD,
|
|
&mListenerQpCondition.mQpBlocknessThreshold) != ECODataStatus::OK ||
|
|
config.findInt32(KEY_LISTENER_QP_CHANGE_THRESHOLD,
|
|
&mListenerQpCondition.mQpChangeThreshold) != ECODataStatus::OK ||
|
|
mListenerQpCondition.mQpBlocknessThreshold < ENCODER_MIN_QP ||
|
|
mListenerQpCondition.mQpBlocknessThreshold > ENCODER_MAX_QP) {
|
|
*status = false;
|
|
ECOLOGE("%s: listener config is invalid", __FUNCTION__);
|
|
return STATUS_ERROR(ERROR_ILLEGAL_ARGUMENT, "listener config is not valid");
|
|
}
|
|
|
|
ECOLOGD("Info listener name: %s uid: %d pid %d", ::android::String8(name).string(),
|
|
IPCThreadState::self()->getCallingUid(), IPCThreadState::self()->getCallingPid());
|
|
|
|
mListener = listener;
|
|
mListenerName = name;
|
|
mNewListenerAdded = true;
|
|
mWorkerWaitCV.notify_all();
|
|
|
|
*status = true;
|
|
return binder::Status::ok();
|
|
}
|
|
|
|
Status ECOSession::removeInfoListener(
|
|
const sp<::android::media::eco::IECOServiceInfoListener>& listener, bool* _aidl_return) {
|
|
std::scoped_lock<std::mutex> lock(mSessionLock);
|
|
// Check if the listener is the same as current listener for the session.
|
|
if (IInterface::asBinder(listener) != IInterface::asBinder(mListener)) {
|
|
*_aidl_return = false;
|
|
ECOLOGE("Failed to remove listener");
|
|
return STATUS_ERROR(ERROR_ILLEGAL_ARGUMENT, "Listener does not match");
|
|
}
|
|
|
|
mListener = nullptr;
|
|
mNewListenerAdded = false;
|
|
*_aidl_return = true;
|
|
return binder::Status::ok();
|
|
}
|
|
|
|
Status ECOSession::pushNewStats(const ::android::media::eco::ECOData& stats, bool* _aidl_return) {
|
|
ECOLOGV("ECOSession get new stats type: %s", stats.getDataTypeString().c_str());
|
|
std::unique_lock<std::mutex> lock(mStatsQueueLock);
|
|
mStatsQueue.push_back(stats);
|
|
mWorkerWaitCV.notify_all();
|
|
*_aidl_return = true;
|
|
return binder::Status::ok();
|
|
}
|
|
|
|
Status ECOSession::getWidth(int32_t* _aidl_return) {
|
|
std::scoped_lock<std::mutex> lock(mSessionLock);
|
|
*_aidl_return = mWidth;
|
|
return binder::Status::ok();
|
|
}
|
|
|
|
Status ECOSession::getHeight(int32_t* _aidl_return) {
|
|
std::scoped_lock<std::mutex> lock(mSessionLock);
|
|
*_aidl_return = mHeight;
|
|
return binder::Status::ok();
|
|
}
|
|
|
|
Status ECOSession::getNumOfListeners(int32_t* _aidl_return) {
|
|
std::scoped_lock<std::mutex> lock(mSessionLock);
|
|
*_aidl_return = (mListener == nullptr ? 0 : 1);
|
|
return binder::Status::ok();
|
|
}
|
|
|
|
Status ECOSession::getNumOfProviders(int32_t* _aidl_return) {
|
|
std::scoped_lock<std::mutex> lock(mSessionLock);
|
|
*_aidl_return = (mProvider == nullptr ? 0 : 1);
|
|
return binder::Status::ok();
|
|
}
|
|
|
|
/*virtual*/ void ECOSession::binderDied(const wp<IBinder>& /*who*/) {
|
|
ECOLOGV("binderDied");
|
|
}
|
|
|
|
status_t ECOSession::dump(int fd, const Vector<String16>& /*args*/) {
|
|
std::scoped_lock<std::mutex> lock(mSessionLock);
|
|
dprintf(fd, "\n== Session Info: ==\n\n");
|
|
dprintf(fd,
|
|
"Width: %d Height: %d isCameraRecording: %d, target-bitrate: %d bps codetype: %d "
|
|
"profile: %d level: %d\n",
|
|
mWidth, mHeight, mIsCameraRecording, mTargetBitrateBps, mCodecType, mCodecProfile,
|
|
mCodecLevel);
|
|
if (mProvider != nullptr) {
|
|
dprintf(fd, "Provider: %s \n", ::android::String8(mProviderName).string());
|
|
}
|
|
if (mListener != nullptr) {
|
|
dprintf(fd, "Listener: %s \n", ::android::String8(mListenerName).string());
|
|
}
|
|
dprintf(fd, "\n===================\n\n");
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
void ECOSession::logStats(const ECOData& data) {
|
|
// Check if mLogStats is true;
|
|
if (!mLogStats || mLogStatsEntries == 0) return;
|
|
|
|
// Check if we need to remove the old entry.
|
|
if (mStatsDebugBuffer.size() >= mLogStatsEntries) {
|
|
mStatsDebugBuffer.pop_front();
|
|
}
|
|
|
|
mStatsDebugBuffer.push_back(data);
|
|
}
|
|
|
|
void ECOSession::logInfos(const ECOData& data) {
|
|
// Check if mLogInfo is true;
|
|
if (!mLogInfo || mLogInfoEntries == 0) return;
|
|
|
|
// Check if we need to remove the old entry.
|
|
if (mInfosDebugBuffer.size() >= mLogInfoEntries) {
|
|
mInfosDebugBuffer.pop_front();
|
|
}
|
|
|
|
mInfosDebugBuffer.push_back(data);
|
|
}
|
|
|
|
} // namespace eco
|
|
} // namespace media
|
|
} // namespace android
|