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

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

VT: RTCP:NACK implementation. (RFC-4585)



 - An implementation of 'RTCP Generic NACK' according to RFC-4585.
 - RTCP:NACK implemented to request retransmit of missed pkts.
   NACK feature is needed to get a higher VMOS score of video call.

Bug: 165061754
Merged-in: I160b85bce22f51bc8f62c9380ee625aa100009ac
Change-Id: I160b85bce22f51bc8f62c9380ee625aa100009ac
Signed-off-by: default avatarByeongjo Park <bjo.park@samsung.com>
parent a6d72e59
Loading
Loading
Loading
Loading
+59 −0
Original line number Diff line number Diff line
@@ -43,6 +43,63 @@ AAVCAssembler::AAVCAssembler(const sp<AMessage> &notify)
AAVCAssembler::~AAVCAssembler() {
}

int32_t AAVCAssembler::addNack(
        const sp<ARTPSource> &source) {
    List<sp<ABuffer>> *queue = source->queue();
    int32_t nackCount = 0;

    List<sp<ABuffer> >::iterator it = queue->begin();

    uint16_t queueHeadSeqNum;
    if (it != queue->end())
        queueHeadSeqNum = (*it)->int32Data();

    // move to the packet after that RTCP:NACK sent.
    while (it != queue->end()) {
        int32_t seqNum = (*it)->int32Data();
        if (seqNum < source->mHighestNackNumber)
            it++;
        else
            break;
    }

    int32_t nackStartAt = -1;

    while (it != queue->end()) {
        int32_t seqBeforeLast = (*it)->int32Data();
        // increase iterator.
        if ((++it) == queue->end())
            break;
        int32_t seqLast = (*it)->int32Data();

        if ((seqLast - seqBeforeLast) < 0) {
            ALOGD("addNack : found end of seqNum from(%d) to(%d)", seqBeforeLast, seqLast);
            source->mHighestNackNumber = 0;
        }

        // missed packet found
        if (seqLast > (seqBeforeLast + 1) &&
            // we didn't send RTCP:NACK for this packet yet.
            (seqLast - 1) > source->mHighestNackNumber) {
            source->mHighestNackNumber = seqLast -1;
            nackStartAt = seqBeforeLast + 1;
            break;
        }

    }

    if (nackStartAt != -1) {
        nackCount = source->mHighestNackNumber - nackStartAt + 1;
        ALOGD("addNack : nackCount=%d, nackFrom=%d, nackTo=%d", nackCount,
            nackStartAt, source->mHighestNackNumber);

        uint16_t mask = (uint16_t)(0xffff) >> (16-nackCount+1);
        source->setSeqNumToNACK(nackStartAt, mask, queueHeadSeqNum);
    }

    return nackCount;
}

ARTPAssembler::AssemblyStatus AAVCAssembler::addNALUnit(
        const sp<ARTPSource> &source) {
    List<sp<ABuffer> > *queue = source->queue();
@@ -74,6 +131,8 @@ ARTPAssembler::AssemblyStatus AAVCAssembler::addNALUnit(
        mShowQueueCnt++;
    }

    AAVCAssembler::addNack(source);

    ALOGV("start=%lld, now=%lld, played=%lld", (long long)startTime,
            (long long)nowTime, (long long)playedTime);
    ALOGV("rtp-time(JB)=%d, played-rtp-time(JB)=%d, expired-rtp-time(JB)=%d isExpired=%d",
+1 −0
Original line number Diff line number Diff line
@@ -47,6 +47,7 @@ private:
    bool mAccessUnitDamaged;
    List<sp<ABuffer> > mNALUnits;

    int32_t addNack(const sp<ARTPSource> &source);
    AssemblyStatus addNALUnit(const sp<ARTPSource> &source);
    void addSingleNALUnit(const sp<ABuffer> &buffer);
    AssemblyStatus addFragmentedNALUnit(List<sp<ABuffer> > *queue);
+11 −0
Original line number Diff line number Diff line
@@ -448,6 +448,17 @@ void ARTPConnection::onPollStreams() {
                continue;
            }

            // addNACK
            sp<ABuffer> buffer = new ABuffer(kMaxUDPSize);
            for (size_t i = 0; i < it->mSources.size(); ++i) {
                buffer->setRange(0, 0);
                int cnt = it->mSources.valueAt(i)->addNACK(buffer);
                if (cnt > 0) {
                    ALOGV("Send NACK for lost %d Packets", cnt);
                    send(&*it, buffer);
                }
            }

            ++it;
        }
    }
+106 −5
Original line number Diff line number Diff line
@@ -48,6 +48,7 @@ ARTPSource::ARTPSource(
      mClockRate(0),
      mJbTime(300), // default jitter buffer time is 300ms.
      mFirstSsrc(0),
      mHighestNackNumber(0),
      mID(id),
      mHighestSeqNumber(0),
      mPrevExpected(0),
@@ -222,7 +223,7 @@ void ARTPSource::addFIR(const sp<ABuffer> &buffer) {
    mLastFIRRequestUs = nowUs;

    if (buffer->size() + 20 > buffer->capacity()) {
        ALOGW("RTCP buffer too small to accomodate FIR.");
        ALOGW("RTCP buffer too small to accommodate FIR.");
        return;
    }

@@ -253,14 +254,14 @@ void ARTPSource::addFIR(const sp<ABuffer> &buffer) {
    data[18] = 0x00;
    data[19] = 0x00;

    buffer->setRange(buffer->offset(), buffer->size() + 20);
    buffer->setRange(buffer->offset(), buffer->size() + (data[3] + 1) * sizeof(int32_t));

    ALOGV("Added FIR request.");
}

void ARTPSource::addReceiverReport(const sp<ABuffer> &buffer) {
    if (buffer->size() + 32 > buffer->capacity()) {
        ALOGW("RTCP buffer too small to accomodate RR.");
        ALOGW("RTCP buffer too small to accommodate RR.");
        return;
    }

@@ -331,7 +332,7 @@ void ARTPSource::addReceiverReport(const sp<ABuffer> &buffer) {
    data[30] = (DLSR >> 8) & 0xff;
    data[31] = DLSR & 0xff;

    buffer->setRange(buffer->offset(), buffer->size() + 32);
    buffer->setRange(buffer->offset(), buffer->size() + (data[3] + 1) * sizeof(int32_t));
}

void ARTPSource::addTMMBR(const sp<ABuffer> &buffer, int32_t targetBitrate) {
@@ -375,7 +376,107 @@ void ARTPSource::addTMMBR(const sp<ABuffer> &buffer, int32_t targetBitrate) {
    data[18] =                        (mantissa & 0x0007f) << 1;
    data[19] = 40;              // 40 bytes overhead;

    buffer->setRange(buffer->offset(), buffer->size() + 20);
    buffer->setRange(buffer->offset(), buffer->size() + (data[3] + 1) * sizeof(int32_t));
}

int ARTPSource::addNACK(const sp<ABuffer> &buffer) {
    if (buffer->size() + 52 > buffer->capacity()) {
        ALOGW("RTCP buffer too small to accomodate NACK.");
        return -1;
    }

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

    data[0] = 0x80 | 1; // Generic NACK
    data[1] = 205;      // TSFB
    data[2] = 0;
    data[3] = 0;        // will be decided later
    data[4] = kSourceID >> 24;
    data[5] = (kSourceID >> 16) & 0xff;
    data[6] = (kSourceID >> 8) & 0xff;
    data[7] = kSourceID & 0xff;

    data[8] = mID >> 24;
    data[9] = (mID >> 16) & 0xff;
    data[10] = (mID >> 8) & 0xff;
    data[11] = mID & 0xff;

    List<int> list;
    List<int>::iterator it;
    getSeqNumToNACK(list, 10);
    int cnt = 0;

    int* FCI = (int*)(data + 12);
    for (it = list.begin() ; it != list.end() ; it++) {
        *(FCI + cnt) = *it;
        cnt++;
    }

    data[3] = (3 + cnt) - 1;  // total (3 + #ofFCI) * sizeof(int32_t) byte

    buffer->setRange(buffer->offset(), buffer->size() + (data[3] + 1) * sizeof(int32_t));

    return cnt;
}

int ARTPSource::getSeqNumToNACK(List<int>& list, int size) {
    AutoMutex _l(mMapLock);
    int cnt = 0;

    std::map<uint16_t, infoNACK>::iterator it;
    for(it = mNACKMap.begin() ; it != mNACKMap.end() ; it++) {
        infoNACK& info_it = it->second;
        // list full
        if (cnt == size)
            break;
        if (info_it.needToNACK) {
            info_it.needToNACK = false;
            // switch LSB to MSB for sending N/W
            uint32_t FCI;
            uint8_t* temp = (uint8_t*)&FCI;
            temp[0] = (info_it.seqNum >> 8) & 0xff;
            temp[1] = (info_it.seqNum)      & 0xff;
            temp[2] = (info_it.mask >> 8)   & 0xff;
            temp[3] = (info_it.mask)        & 0xff;

            list.push_back(FCI);
            cnt++;
        }
    }

    return cnt;
}

void ARTPSource::setSeqNumToNACK(uint16_t seqNum, uint16_t mask, uint16_t nowJitterHeadSeqNum) {
    AutoMutex _l(mMapLock);
    infoNACK info = {seqNum, mask, nowJitterHeadSeqNum, true};
    std::map<uint16_t, infoNACK>::iterator it;

    it = mNACKMap.find(seqNum);
    if (it != mNACKMap.end()) {
        infoNACK& info_it = it->second;
        // renew if (mask or head seq) is changed
        if((info_it.mask != mask) || (info_it.nowJitterHeadSeqNum != nowJitterHeadSeqNum)) {
            info_it = info;
        }
    } else {
        mNACKMap[seqNum] = info;
    }

    // delete all NACK far from current Jitter's first sequence number
    it = mNACKMap.begin();
    while(it != mNACKMap.end()) {
        infoNACK& info_it = it->second;

        int diff = nowJitterHeadSeqNum - info_it.nowJitterHeadSeqNum;
        if (diff > 100) {
            ALOGV("Delete %d pkt from NACK map ", info_it.seqNum);
            it = mNACKMap.erase(it);
        }
        else
            it++;
    }

}

uint32_t ARTPSource::getSelfID() {
+17 −0
Original line number Diff line number Diff line
@@ -23,6 +23,9 @@
#include <media/stagefright/foundation/ABase.h>
#include <utils/List.h>
#include <utils/RefBase.h>
#include <utils/Thread.h>

#include <map>

namespace android {

@@ -46,6 +49,8 @@ struct ARTPSource : public RefBase {
    void addReceiverReport(const sp<ABuffer> &buffer);
    void addFIR(const sp<ABuffer> &buffer);
    void addTMMBR(const sp<ABuffer> &buffer, int32_t targetBitrate);
    int addNACK(const sp<ABuffer> &buffer);
    void setSeqNumToNACK(uint16_t seqNum, uint16_t mask, uint16_t nowJitterHeadSeqNum);
    uint32_t getSelfID();
    void setSelfID(const uint32_t selfID);
    void setJbTime(const uint32_t jbTime);
@@ -60,6 +65,7 @@ struct ARTPSource : public RefBase {

    uint32_t mJbTime;
    int32_t mFirstSsrc;
    int32_t mHighestNackNumber;

private:

@@ -75,6 +81,17 @@ private:
    List<sp<ABuffer> > mQueue;
    sp<ARTPAssembler> mAssembler;

    typedef struct infoNACK {
        uint16_t seqNum;
        uint16_t mask;
        uint16_t nowJitterHeadSeqNum;
        bool    needToNACK;
    } infoNACK;

    Mutex mMapLock;
    std::map<uint16_t, infoNACK> mNACKMap;
    int getSeqNumToNACK(List<int>& list, int size);

    uint64_t mLastNTPTime;
    int64_t mLastNTPTimeUpdateUs;