Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a5062c42 authored by Kim Sungyeon's avatar Kim Sungyeon Committed by Lajos Molnar
Browse files

VT: Postpone bitrate down for considering camera switch



1. If received packet is too few, it has a possibility that opponent switches camera
   For that possibility postpone bitrate down for 3 seconds.
2. A thread class form a concept of timer is implemented.
   These are introduced to support QualManager's timer operations like (1.)
3. License message added

Merged-in: I6b69cbb555eec99bf45dc77ba5e24affdbcd3776
Change-Id: I6b69cbb555eec99bf45dc77ba5e24affdbcd3776
Signed-off-by: default avatarKim Sungyeon <sy85.kim@samsung.com>
parent a2530aee
Loading
Loading
Loading
Loading
+5 −5
Original line number Diff line number Diff line
@@ -267,8 +267,6 @@ void ARTPSource::addReceiverReport(const sp<ABuffer> &buffer) {
    mPrevNumBuffersReceived = mNumBuffersReceived;
    int32_t cumulativePacketLost = (int32_t)expected - mNumBuffersReceived;

    ALOGI("UID %p expectedPkts %lld lostPkts %lld", this, (long long)intervalExpected, (long long)intervalPacketLost);

    uint8_t *data = buffer->data() + buffer->size();

    data[0] = 0x80 | 1;
@@ -392,14 +390,16 @@ void ARTPSource::setTargetBitrate() {
    int64_t intervalReceived = mNumBuffersReceived - mPrevNumBuffersReceived;
    int64_t intervalPacketLost = intervalExpected - intervalReceived;

    if (intervalPacketLost < 0)
    ALOGI("UID %p expectedPkts %lld lostPkts %lld", this, (long long)intervalExpected, (long long)intervalPacketLost);

    if (intervalPacketLost < 0 || intervalExpected == 0)
        fraction = 0;
    else if (intervalExpected <= intervalPacketLost || intervalExpected == 0)
    else if (intervalExpected <= intervalPacketLost)
        fraction = 255;
    else
        fraction = (intervalPacketLost << 8) / intervalExpected;

    mQualManager.setTargetBitrate(fraction, ALooper::GetNowUs());
    mQualManager.setTargetBitrate(fraction, ALooper::GetNowUs(), intervalExpected < 5);
}

bool ARTPSource::isNeedToReport() {
+1 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ cc_defaults {
        "ARTSPConnection.cpp",
        "ASessionDescription.cpp",
        "SDPLoader.cpp",
        "QualManager.cpp",
    ],

    shared_libs: [
+174 −0
Original line number Diff line number Diff line
/*
 * 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
+36 −70
Original line number Diff line number Diff line
@@ -18,92 +18,58 @@

#define QUAL_MANAGER_H_

namespace android {
#include <stdint.h>
#include <utils/Thread.h>

namespace android {
class QualManager {
public:
    QualManager() : mMinBitrate(-1), mMaxBitrate(-1), mTargetBitrate(512000),
                    mLastTargetBitrate(-1), mLastSetBitrateTime(0),
                    mLowBitrateStartTime(0), mAutoDowngrade(false),
                    mIsNewTargetBitrate(false){};
    QualManager();
    ~QualManager();

    int32_t getTargetBitrate() {
        if (mIsNewTargetBitrate) {
            mIsNewTargetBitrate = false;
            mLastTargetBitrate = mTargetBitrate;
            return mTargetBitrate;
        } else {
            return -1;
        }
    }
    int32_t getTargetBitrate();
    bool isNeedToDowngrade();

    bool isNeedToDowngrade() {
        return mAutoDowngrade;
    }
    void setTargetBitrate(uint8_t fraction, int64_t nowUs, bool isTooLowPkts);
    void setMinMaxBitrate(int32_t min, int32_t max);
    void setBitrateData(int32_t bitrate, int64_t now);
private:
    class Watcher : public Thread
    {
    public:
        Watcher(int32_t timeLimit);

    void setTargetBitrate(uint8_t fraction, int64_t nowUs) {
        if (fraction <= (256 * 2 /100)) {           // loss less than 2%
            mTargetBitrate += mBitrateStep;
        } else if (fraction > (256 * 5 / 100)) {    // loss more than 5%
            mTargetBitrate -= mBitrateStep * 4;
        }
        void setup();
        void release();
        void exit();
        bool isExpired() const;
    private:
        virtual ~Watcher();
        virtual bool threadLoop();

        if (mTargetBitrate > mMaxBitrate) {
            mTargetBitrate = mMaxBitrate;
        } else if (mTargetBitrate < mMinBitrate) {
            if (mLowBitrateStartTime != 0) {
                mLowBitrateStartTime = nowUs;
            }
            mTargetBitrate = mMinBitrate;
        }
        char name[32] = {0,};

        if (mLastTargetBitrate != mTargetBitrate || nowUs - mLastSetBitrateTime > 5000000ll) {
            mIsNewTargetBitrate = true;
            mLastSetBitrateTime = nowUs;
        }
    };
        Condition mMyCond;
        Mutex mMyLock;

    void setMinMaxBitrate(int32_t min, int32_t max) {
        mMinBitrate = min;
        mMaxBitrate = max;
        mBitrateStep = (max - min) / 8;
        bool mWatching;
        bool mSwitch;
        const nsecs_t mTimeLimit;
    };

    void setBitrateData(int32_t bitrate, int64_t now) {
        int64_t lowBitrateDuration = 0;
        if (bitrate < mMinBitrate)
        {
            if (mLowBitrateStartTime == 0) {
                mLowBitrateStartTime = now;
            } else {
                lowBitrateDuration = now - mLowBitrateStartTime;
            }
        } else {
            mLowBitrateStartTime = 0;
        }
        if (lowBitrateDuration > mPatientTime) {
            mAutoDowngrade = true;
        } else {
            mAutoDowngrade = false;
        }
    }
private:
    sp<Watcher> VFPWatcher;
    sp<Watcher> LBRWatcher;
    int32_t mMinBitrate;
    int32_t mMaxBitrate;
    int32_t mBitrateStep;

    int32_t mTargetBitrate;
    int32_t mLastTargetBitrate;

    int64_t mLastSetBitrateTime;

    const int64_t mPatientTime = 10000000ll;    // 10 sec
    int64_t mLowBitrateStartTime;

    bool mAutoDowngrade;
    bool mIsNewTargetBitrate;
};

    int32_t clampingBitrate(int32_t bitrate);
};
} //namespace android

#endif  // QUAL_MANAGER_H_