blob: 37aa326af0e13d290f55ed8c294f2264b4496fc7 [file] [log] [blame]
/*
* Copyright (C) 2018 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 "QualManager"
#include <algorithm>
#include <sys/prctl.h>
#include <utils/Log.h>
#include "QualManager.h"
namespace android {
QualManager::Watcher::Watcher(int32_t timeLimit)
: Thread(false), mWatching(false), mSwitch(false),
mTimeLimit(timeLimit * 1000000LL) // timeLimit ms
{
}
bool QualManager::Watcher::isExpired() const
{
return mSwitch;
}
void QualManager::Watcher::setup() {
AutoMutex _l(mMyLock);
if (mWatching == false) {
mWatching = true;
mMyCond.signal();
}
}
void QualManager::Watcher::release() {
AutoMutex _l(mMyLock);
if (mSwitch) {
ALOGW("%s DISARMED", name);
mSwitch = false;
}
if (mWatching == true) {
ALOGW("%s DISARMED", name);
mWatching = false;
mMyCond.signal();
}
}
void QualManager::Watcher::exit() {
AutoMutex _l(mMyLock);
// The order is important to avoid dead lock.
Thread::requestExit();
mMyCond.signal();
}
QualManager::Watcher::~Watcher() {
ALOGI("%s thread dead", name);
}
bool QualManager::Watcher::threadLoop() {
AutoMutex _l(mMyLock);
#if defined(__linux__)
prctl(PR_GET_NAME, name, 0, 0, 0);
#endif
while (!exitPending()) {
ALOGW("%s Timer init", name);
mMyCond.wait(mMyLock); // waits as non-watching state
if (exitPending())
return false;
ALOGW("%s timer BOOM after %d msec", name, (int)(mTimeLimit / 1000000LL));
mMyCond.waitRelative(mMyLock, mTimeLimit); // waits as watching satte
if (mWatching == true) {
mSwitch = true;
ALOGW("%s BOOM!!!!", name);
}
mWatching = false;
}
return false;
}
QualManager::QualManager()
: mMinBitrate(-1), mMaxBitrate(-1),
mTargetBitrate(512000), mLastTargetBitrate(-1),
mLastSetBitrateTime(0), mIsNewTargetBitrate(false)
{
VFPWatcher = new Watcher(3000); //Very Few Packet Watcher
VFPWatcher->run("VeryFewPtk");
LBRWatcher = new Watcher(10000); //Low Bit Rate Watcher
LBRWatcher->run("LowBitRate");
}
QualManager::~QualManager() {
VFPWatcher->exit();
LBRWatcher->exit();
}
int32_t QualManager::getTargetBitrate() {
if (mIsNewTargetBitrate) {
mIsNewTargetBitrate = false;
mLastTargetBitrate = clampingBitrate(mTargetBitrate);
mTargetBitrate = mLastTargetBitrate;
return mTargetBitrate;
} else {
return -1;
}
}
bool QualManager::isNeedToDowngrade() {
return LBRWatcher->isExpired();
}
void QualManager::setTargetBitrate(uint8_t fraction, int64_t nowUs, bool isTooLowPkts) {
/* Too Low Packet. Maybe opponent is switching camera.
* If this condition goes longer, we should down bitrate.
*/
if (isTooLowPkts) {
VFPWatcher->setup();
} else {
VFPWatcher->release();
}
if ((fraction > (256 * 5 / 100) && !isTooLowPkts) || VFPWatcher->isExpired()) {
// loss more than 5% or VFPWatcher BOOMED
mTargetBitrate -= mBitrateStep * 3;
} else if (fraction <= (256 * 2 /100)) {
// loss less than 2%
mTargetBitrate += mBitrateStep;
}
if (mTargetBitrate > mMaxBitrate) {
mTargetBitrate = mMaxBitrate + mBitrateStep;
} else if (mTargetBitrate < mMinBitrate) {
LBRWatcher->setup();
mTargetBitrate = mMinBitrate - mBitrateStep;
}
if (mLastTargetBitrate != clampingBitrate(mTargetBitrate) ||
nowUs - mLastSetBitrateTime > 5000000ll) {
mIsNewTargetBitrate = true;
mLastSetBitrateTime = nowUs;
}
}
void QualManager::setMinMaxBitrate(int32_t min, int32_t max) {
mMinBitrate = min;
mMaxBitrate = max;
mBitrateStep = (max - min) / 8;
}
void QualManager::setBitrateData(int32_t bitrate, int64_t /*now*/) {
// A bitrate that is considered packetloss also should be good.
if (bitrate >= mMinBitrate && mTargetBitrate >= mMinBitrate) {
LBRWatcher->release();
} else if (bitrate < mMinBitrate){
LBRWatcher->setup();
}
}
int32_t QualManager::clampingBitrate(int32_t bitrate) {
return std::min(std::max(mMinBitrate, bitrate), mMaxBitrate);
}
} // namespace android