/*
 * Copyright 2013, 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 "RTPReceiver"
#include <utils/Log.h>

#include "RTPAssembler.h"
#include "RTPReceiver.h"

#include "ANetworkSession.h"

#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/foundation/hexdump.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/Utils.h>

#define TRACK_PACKET_LOSS       0

namespace android {

////////////////////////////////////////////////////////////////////////////////

struct RTPReceiver::Source : public AHandler {
    Source(RTPReceiver *receiver, uint32_t ssrc);

    void onPacketReceived(uint16_t seq, const sp<ABuffer> &buffer);

    void addReportBlock(uint32_t ssrc, const sp<ABuffer> &buf);

protected:
    virtual ~Source();

    virtual void onMessageReceived(const sp<AMessage> &msg);

private:
    enum {
        kWhatRetransmit,
        kWhatDeclareLost,
    };

    static const uint32_t kMinSequential = 2;
    static const uint32_t kMaxDropout = 3000;
    static const uint32_t kMaxMisorder = 100;
    static const uint32_t kRTPSeqMod = 1u << 16;
    static const int64_t kReportIntervalUs = 10000000ll;

    RTPReceiver *mReceiver;
    uint32_t mSSRC;
    bool mFirst;
    uint16_t mMaxSeq;
    uint32_t mCycles;
    uint32_t mBaseSeq;
    uint32_t mReceived;
    uint32_t mExpectedPrior;
    uint32_t mReceivedPrior;

    int64_t mFirstArrivalTimeUs;
    int64_t mFirstRTPTimeUs;

    // Ordered by extended seq number.
    List<sp<ABuffer> > mPackets;

    enum StatusBits {
        STATUS_DECLARED_LOST            = 1,
        STATUS_REQUESTED_RETRANSMISSION = 2,
        STATUS_ARRIVED_LATE             = 4,
    };
#if TRACK_PACKET_LOSS
    KeyedVector<int32_t, uint32_t> mLostPackets;
#endif

    void modifyPacketStatus(int32_t extSeqNo, uint32_t mask);

    int32_t mAwaitingExtSeqNo;
    bool mRequestedRetransmission;

    int32_t mActivePacketType;
    sp<Assembler> mActiveAssembler;

    int64_t mNextReportTimeUs;

    int32_t mNumDeclaredLost;
    int32_t mNumDeclaredLostPrior;

    int32_t mRetransmitGeneration;
    int32_t mDeclareLostGeneration;
    bool mDeclareLostTimerPending;

    void queuePacket(const sp<ABuffer> &packet);
    void dequeueMore();

    sp<ABuffer> getNextPacket();
    void resync();

    void postRetransmitTimer(int64_t delayUs);
    void postDeclareLostTimer(int64_t delayUs);
    void cancelTimers();

    DISALLOW_EVIL_CONSTRUCTORS(Source);
};

////////////////////////////////////////////////////////////////////////////////

RTPReceiver::Source::Source(RTPReceiver *receiver, uint32_t ssrc)
    : mReceiver(receiver),
      mSSRC(ssrc),
      mFirst(true),
      mMaxSeq(0),
      mCycles(0),
      mBaseSeq(0),
      mReceived(0),
      mExpectedPrior(0),
      mReceivedPrior(0),
      mFirstArrivalTimeUs(-1ll),
      mFirstRTPTimeUs(-1ll),
      mAwaitingExtSeqNo(-1),
      mRequestedRetransmission(false),
      mActivePacketType(-1),
      mNextReportTimeUs(-1ll),
      mNumDeclaredLost(0),
      mNumDeclaredLostPrior(0),
      mRetransmitGeneration(0),
      mDeclareLostGeneration(0),
      mDeclareLostTimerPending(false) {
}

RTPReceiver::Source::~Source() {
}

void RTPReceiver::Source::onMessageReceived(const sp<AMessage> &msg) {
    switch (msg->what()) {
        case kWhatRetransmit:
        {
            int32_t generation;
            CHECK(msg->findInt32("generation", &generation));

            if (generation != mRetransmitGeneration) {
                break;
            }

            mRequestedRetransmission = true;
            mReceiver->requestRetransmission(mSSRC, mAwaitingExtSeqNo);

            modifyPacketStatus(
                    mAwaitingExtSeqNo, STATUS_REQUESTED_RETRANSMISSION);
            break;
        }

        case kWhatDeclareLost:
        {
            int32_t generation;
            CHECK(msg->findInt32("generation", &generation));

            if (generation != mDeclareLostGeneration) {
                break;
            }

            cancelTimers();

            ALOGV("Lost packet extSeqNo %d %s",
                  mAwaitingExtSeqNo,
                  mRequestedRetransmission ? "*" : "");

            mRequestedRetransmission = false;
            if (mActiveAssembler != NULL) {
                mActiveAssembler->signalDiscontinuity();
            }

            modifyPacketStatus(mAwaitingExtSeqNo, STATUS_DECLARED_LOST);

            // resync();
            ++mAwaitingExtSeqNo;
            ++mNumDeclaredLost;

            mReceiver->notifyPacketLost();

            dequeueMore();
            break;
        }

        default:
            TRESPASS();
    }
}

void RTPReceiver::Source::onPacketReceived(
        uint16_t seq, const sp<ABuffer> &buffer) {
    if (mFirst) {
        buffer->setInt32Data(mCycles | seq);
        queuePacket(buffer);

        mFirst = false;
        mBaseSeq = seq;
        mMaxSeq = seq;
        ++mReceived;
        return;
    }

    uint16_t udelta = seq - mMaxSeq;

    if (udelta < kMaxDropout) {
        // In order, with permissible gap.

        if (seq < mMaxSeq) {
            // Sequence number wrapped - count another 64K cycle
            mCycles += kRTPSeqMod;
        }

        mMaxSeq = seq;

        ++mReceived;
    } else if (udelta <= kRTPSeqMod - kMaxMisorder) {
        // The sequence number made a very large jump
        return;
    } else {
        // Duplicate or reordered packet.
    }

    buffer->setInt32Data(mCycles | seq);
    queuePacket(buffer);
}

void RTPReceiver::Source::queuePacket(const sp<ABuffer> &packet) {
    int32_t newExtendedSeqNo = packet->int32Data();

    if (mFirstArrivalTimeUs < 0ll) {
        mFirstArrivalTimeUs = ALooper::GetNowUs();

        uint32_t rtpTime;
        CHECK(packet->meta()->findInt32("rtp-time", (int32_t *)&rtpTime));

        mFirstRTPTimeUs = (rtpTime * 100ll) / 9ll;
    }

    if (mAwaitingExtSeqNo >= 0 && newExtendedSeqNo < mAwaitingExtSeqNo) {
        // We're no longer interested in these. They're old.
        ALOGV("dropping stale extSeqNo %d", newExtendedSeqNo);

        modifyPacketStatus(newExtendedSeqNo, STATUS_ARRIVED_LATE);
        return;
    }

    if (mPackets.empty()) {
        mPackets.push_back(packet);
        dequeueMore();
        return;
    }

    List<sp<ABuffer> >::iterator firstIt = mPackets.begin();
    List<sp<ABuffer> >::iterator it = --mPackets.end();
    for (;;) {
        int32_t extendedSeqNo = (*it)->int32Data();

        if (extendedSeqNo == newExtendedSeqNo) {
            // Duplicate packet.
            return;
        }

        if (extendedSeqNo < newExtendedSeqNo) {
            // Insert new packet after the one at "it".
            mPackets.insert(++it, packet);
            break;
        }

        if (it == firstIt) {
            // Insert new packet before the first existing one.
            mPackets.insert(it, packet);
            break;
        }

        --it;
    }

    dequeueMore();
}

void RTPReceiver::Source::dequeueMore() {
    int64_t nowUs = ALooper::GetNowUs();
    if (mNextReportTimeUs < 0ll || nowUs >= mNextReportTimeUs) {
        if (mNextReportTimeUs >= 0ll) {
            uint32_t expected = (mMaxSeq | mCycles) - mBaseSeq + 1;

            uint32_t expectedInterval = expected - mExpectedPrior;
            mExpectedPrior = expected;

            uint32_t receivedInterval = mReceived - mReceivedPrior;
            mReceivedPrior = mReceived;

            int64_t lostInterval =
                (int64_t)expectedInterval - (int64_t)receivedInterval;

            int32_t declaredLostInterval =
                mNumDeclaredLost - mNumDeclaredLostPrior;

            mNumDeclaredLostPrior = mNumDeclaredLost;

            if (declaredLostInterval > 0) {
                ALOGI("lost %lld packets (%.2f %%), declared %d lost\n",
                      lostInterval,
                      100.0f * lostInterval / expectedInterval,
                      declaredLostInterval);
            }
        }

        mNextReportTimeUs = nowUs + kReportIntervalUs;

#if TRACK_PACKET_LOSS
        for (size_t i = 0; i < mLostPackets.size(); ++i) {
            int32_t key = mLostPackets.keyAt(i);
            uint32_t value = mLostPackets.valueAt(i);

            AString status;
            if (value & STATUS_REQUESTED_RETRANSMISSION) {
                status.append("retrans ");
            }
            if (value & STATUS_ARRIVED_LATE) {
                status.append("arrived-late ");
            }
            ALOGI("Packet %d declared lost %s", key, status.c_str());
        }
#endif
    }

    sp<ABuffer> packet;
    while ((packet = getNextPacket()) != NULL) {
        if (mDeclareLostTimerPending) {
            cancelTimers();
        }

        CHECK_GE(mAwaitingExtSeqNo, 0);
#if TRACK_PACKET_LOSS
        mLostPackets.removeItem(mAwaitingExtSeqNo);
#endif

        int32_t packetType;
        CHECK(packet->meta()->findInt32("PT", &packetType));

        if (packetType != mActivePacketType) {
            mActiveAssembler = mReceiver->makeAssembler(packetType);
            mActivePacketType = packetType;
        }

        if (mActiveAssembler != NULL) {
            status_t err = mActiveAssembler->processPacket(packet);
            if (err != OK) {
                ALOGV("assembler returned error %d", err);
            }
        }

        ++mAwaitingExtSeqNo;
    }

    if (mDeclareLostTimerPending) {
        return;
    }

    if (mPackets.empty()) {
        return;
    }

    CHECK_GE(mAwaitingExtSeqNo, 0);

    const sp<ABuffer> &firstPacket = *mPackets.begin();

    uint32_t rtpTime;
    CHECK(firstPacket->meta()->findInt32(
                "rtp-time", (int32_t *)&rtpTime));


    int64_t rtpUs = (rtpTime * 100ll) / 9ll;

    int64_t maxArrivalTimeUs =
        mFirstArrivalTimeUs + rtpUs - mFirstRTPTimeUs;

    nowUs = ALooper::GetNowUs();

    CHECK_LT(mAwaitingExtSeqNo, firstPacket->int32Data());

    ALOGV("waiting for %d, comparing against %d, %lld us left",
          mAwaitingExtSeqNo,
          firstPacket->int32Data(),
          maxArrivalTimeUs - nowUs);

    postDeclareLostTimer(maxArrivalTimeUs + kPacketLostAfterUs);

    if (kRequestRetransmissionAfterUs > 0ll) {
        postRetransmitTimer(
                maxArrivalTimeUs + kRequestRetransmissionAfterUs);
    }
}

sp<ABuffer> RTPReceiver::Source::getNextPacket() {
    if (mPackets.empty()) {
        return NULL;
    }

    int32_t extSeqNo = (*mPackets.begin())->int32Data();

    if (mAwaitingExtSeqNo < 0) {
        mAwaitingExtSeqNo = extSeqNo;
    } else if (extSeqNo != mAwaitingExtSeqNo) {
        return NULL;
    }

    sp<ABuffer> packet = *mPackets.begin();
    mPackets.erase(mPackets.begin());

    return packet;
}

void RTPReceiver::Source::resync() {
    mAwaitingExtSeqNo = -1;
}

void RTPReceiver::Source::addReportBlock(
        uint32_t ssrc, const sp<ABuffer> &buf) {
    uint32_t extMaxSeq = mMaxSeq | mCycles;
    uint32_t expected = extMaxSeq - mBaseSeq + 1;

    int64_t lost = (int64_t)expected - (int64_t)mReceived;
    if (lost > 0x7fffff) {
        lost = 0x7fffff;
    } else if (lost < -0x800000) {
        lost = -0x800000;
    }

    uint32_t expectedInterval = expected - mExpectedPrior;
    mExpectedPrior = expected;

    uint32_t receivedInterval = mReceived - mReceivedPrior;
    mReceivedPrior = mReceived;

    int64_t lostInterval = expectedInterval - receivedInterval;

    uint8_t fractionLost;
    if (expectedInterval == 0 || lostInterval <=0) {
        fractionLost = 0;
    } else {
        fractionLost = (lostInterval << 8) / expectedInterval;
    }

    uint8_t *ptr = buf->data() + buf->size();

    ptr[0] = ssrc >> 24;
    ptr[1] = (ssrc >> 16) & 0xff;
    ptr[2] = (ssrc >> 8) & 0xff;
    ptr[3] = ssrc & 0xff;

    ptr[4] = fractionLost;

    ptr[5] = (lost >> 16) & 0xff;
    ptr[6] = (lost >> 8) & 0xff;
    ptr[7] = lost & 0xff;

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

    // XXX TODO:

    ptr[12] = 0x00;  // interarrival jitter
    ptr[13] = 0x00;
    ptr[14] = 0x00;
    ptr[15] = 0x00;

    ptr[16] = 0x00;  // last SR
    ptr[17] = 0x00;
    ptr[18] = 0x00;
    ptr[19] = 0x00;

    ptr[20] = 0x00;  // delay since last SR
    ptr[21] = 0x00;
    ptr[22] = 0x00;
    ptr[23] = 0x00;
}

////////////////////////////////////////////////////////////////////////////////

RTPReceiver::RTPReceiver(
        const sp<ANetworkSession> &netSession,
        const sp<AMessage> &notify,
        uint32_t flags)
    : mNetSession(netSession),
      mNotify(notify),
      mFlags(flags),
      mRTPMode(TRANSPORT_UNDEFINED),
      mRTCPMode(TRANSPORT_UNDEFINED),
      mRTPSessionID(0),
      mRTCPSessionID(0),
      mRTPConnected(false),
      mRTCPConnected(false),
      mRTPClientSessionID(0),
      mRTCPClientSessionID(0) {
}

RTPReceiver::~RTPReceiver() {
    if (mRTCPClientSessionID != 0) {
        mNetSession->destroySession(mRTCPClientSessionID);
        mRTCPClientSessionID = 0;
    }

    if (mRTPClientSessionID != 0) {
        mNetSession->destroySession(mRTPClientSessionID);
        mRTPClientSessionID = 0;
    }

    if (mRTCPSessionID != 0) {
        mNetSession->destroySession(mRTCPSessionID);
        mRTCPSessionID = 0;
    }

    if (mRTPSessionID != 0) {
        mNetSession->destroySession(mRTPSessionID);
        mRTPSessionID = 0;
    }
}

status_t RTPReceiver::initAsync(
        TransportMode rtpMode,
        TransportMode rtcpMode,
        int32_t *outLocalRTPPort) {
    if (mRTPMode != TRANSPORT_UNDEFINED
            || rtpMode == TRANSPORT_UNDEFINED
            || rtpMode == TRANSPORT_NONE
            || rtcpMode == TRANSPORT_UNDEFINED) {
        return INVALID_OPERATION;
    }

    CHECK_NE(rtpMode, TRANSPORT_TCP_INTERLEAVED);
    CHECK_NE(rtcpMode, TRANSPORT_TCP_INTERLEAVED);

    sp<AMessage> rtpNotify = new AMessage(kWhatRTPNotify, id());

    sp<AMessage> rtcpNotify;
    if (rtcpMode != TRANSPORT_NONE) {
        rtcpNotify = new AMessage(kWhatRTCPNotify, id());
    }

    CHECK_EQ(mRTPSessionID, 0);
    CHECK_EQ(mRTCPSessionID, 0);

    int32_t localRTPPort;

    struct in_addr ifaceAddr;
    ifaceAddr.s_addr = INADDR_ANY;

    for (;;) {
        localRTPPort = PickRandomRTPPort();

        status_t err;
        if (rtpMode == TRANSPORT_UDP) {
            err = mNetSession->createUDPSession(
                    localRTPPort,
                    rtpNotify,
                    &mRTPSessionID);
        } else {
            CHECK_EQ(rtpMode, TRANSPORT_TCP);
            err = mNetSession->createTCPDatagramSession(
                    ifaceAddr,
                    localRTPPort,
                    rtpNotify,
                    &mRTPSessionID);
        }

        if (err != OK) {
            continue;
        }

        if (rtcpMode == TRANSPORT_NONE) {
            break;
        } else if (rtcpMode == TRANSPORT_UDP) {
            err = mNetSession->createUDPSession(
                    localRTPPort + 1,
                    rtcpNotify,
                    &mRTCPSessionID);
        } else {
            CHECK_EQ(rtpMode, TRANSPORT_TCP);
            err = mNetSession->createTCPDatagramSession(
                    ifaceAddr,
                    localRTPPort + 1,
                    rtcpNotify,
                    &mRTCPSessionID);
        }

        if (err == OK) {
            break;
        }

        mNetSession->destroySession(mRTPSessionID);
        mRTPSessionID = 0;
    }

    mRTPMode = rtpMode;
    mRTCPMode = rtcpMode;
    *outLocalRTPPort = localRTPPort;

    return OK;
}

status_t RTPReceiver::connect(
        const char *remoteHost, int32_t remoteRTPPort, int32_t remoteRTCPPort) {
    status_t err;

    if (mRTPMode == TRANSPORT_UDP) {
        CHECK(!mRTPConnected);

        err = mNetSession->connectUDPSession(
                mRTPSessionID, remoteHost, remoteRTPPort);

        if (err != OK) {
            notifyInitDone(err);
            return err;
        }

        ALOGI("connectUDPSession RTP successful.");

        mRTPConnected = true;
    }

    if (mRTCPMode == TRANSPORT_UDP) {
        CHECK(!mRTCPConnected);

        err = mNetSession->connectUDPSession(
                mRTCPSessionID, remoteHost, remoteRTCPPort);

        if (err != OK) {
            notifyInitDone(err);
            return err;
        }

        scheduleSendRR();

        ALOGI("connectUDPSession RTCP successful.");

        mRTCPConnected = true;
    }

    if (mRTPConnected
            && (mRTCPConnected || mRTCPMode == TRANSPORT_NONE)) {
        notifyInitDone(OK);
    }

    return OK;
}

status_t RTPReceiver::informSender(const sp<AMessage> &params) {
    if (!mRTCPConnected) {
        return INVALID_OPERATION;
    }

    int64_t avgLatencyUs;
    CHECK(params->findInt64("avgLatencyUs", &avgLatencyUs));

    int64_t maxLatencyUs;
    CHECK(params->findInt64("maxLatencyUs", &maxLatencyUs));

    sp<ABuffer> buf = new ABuffer(28);

    uint8_t *ptr = buf->data();
    ptr[0] = 0x80 | 0;
    ptr[1] = 204;  // APP
    ptr[2] = 0;

    CHECK((buf->size() % 4) == 0u);
    ptr[3] = (buf->size() / 4) - 1;

    ptr[4] = kSourceID >> 24;  // SSRC
    ptr[5] = (kSourceID >> 16) & 0xff;
    ptr[6] = (kSourceID >> 8) & 0xff;
    ptr[7] = kSourceID & 0xff;
    ptr[8] = 'l';
    ptr[9] = 'a';
    ptr[10] = 't';
    ptr[11] = 'e';

    ptr[12] = avgLatencyUs >> 56;
    ptr[13] = (avgLatencyUs >> 48) & 0xff;
    ptr[14] = (avgLatencyUs >> 40) & 0xff;
    ptr[15] = (avgLatencyUs >> 32) & 0xff;
    ptr[16] = (avgLatencyUs >> 24) & 0xff;
    ptr[17] = (avgLatencyUs >> 16) & 0xff;
    ptr[18] = (avgLatencyUs >> 8) & 0xff;
    ptr[19] = avgLatencyUs & 0xff;

    ptr[20] = maxLatencyUs >> 56;
    ptr[21] = (maxLatencyUs >> 48) & 0xff;
    ptr[22] = (maxLatencyUs >> 40) & 0xff;
    ptr[23] = (maxLatencyUs >> 32) & 0xff;
    ptr[24] = (maxLatencyUs >> 24) & 0xff;
    ptr[25] = (maxLatencyUs >> 16) & 0xff;
    ptr[26] = (maxLatencyUs >> 8) & 0xff;
    ptr[27] = maxLatencyUs & 0xff;

    mNetSession->sendRequest(mRTCPSessionID, buf->data(), buf->size());

    return OK;
}

void RTPReceiver::onMessageReceived(const sp<AMessage> &msg) {
    switch (msg->what()) {
        case kWhatRTPNotify:
        case kWhatRTCPNotify:
            onNetNotify(msg->what() == kWhatRTPNotify, msg);
            break;

        case kWhatSendRR:
        {
            onSendRR();
            break;
        }

        default:
            TRESPASS();
    }
}

void RTPReceiver::onNetNotify(bool isRTP, const sp<AMessage> &msg) {
    int32_t reason;
    CHECK(msg->findInt32("reason", &reason));

    switch (reason) {
        case ANetworkSession::kWhatError:
        {
            int32_t sessionID;
            CHECK(msg->findInt32("sessionID", &sessionID));

            int32_t err;
            CHECK(msg->findInt32("err", &err));

            int32_t errorOccuredDuringSend;
            CHECK(msg->findInt32("send", &errorOccuredDuringSend));

            AString detail;
            CHECK(msg->findString("detail", &detail));

            ALOGE("An error occurred during %s in session %d "
                  "(%d, '%s' (%s)).",
                  errorOccuredDuringSend ? "send" : "receive",
                  sessionID,
                  err,
                  detail.c_str(),
                  strerror(-err));

            mNetSession->destroySession(sessionID);

            if (sessionID == mRTPSessionID) {
                mRTPSessionID = 0;
            } else if (sessionID == mRTCPSessionID) {
                mRTCPSessionID = 0;
            } else if (sessionID == mRTPClientSessionID) {
                mRTPClientSessionID = 0;
            } else if (sessionID == mRTCPClientSessionID) {
                mRTCPClientSessionID = 0;
            }

            if (!mRTPConnected
                    || (mRTCPMode != TRANSPORT_NONE && !mRTCPConnected)) {
                notifyInitDone(err);
                break;
            }

            notifyError(err);
            break;
        }

        case ANetworkSession::kWhatDatagram:
        {
            sp<ABuffer> data;
            CHECK(msg->findBuffer("data", &data));

            if (isRTP) {
                if (mFlags & FLAG_AUTO_CONNECT) {
                    AString fromAddr;
                    CHECK(msg->findString("fromAddr", &fromAddr));

                    int32_t fromPort;
                    CHECK(msg->findInt32("fromPort", &fromPort));

                    CHECK_EQ((status_t)OK,
                             connect(
                                 fromAddr.c_str(), fromPort, fromPort + 1));

                    mFlags &= ~FLAG_AUTO_CONNECT;
                }

                onRTPData(data);
            } else {
                onRTCPData(data);
            }
            break;
        }

        case ANetworkSession::kWhatClientConnected:
        {
            int32_t sessionID;
            CHECK(msg->findInt32("sessionID", &sessionID));

            if (isRTP) {
                CHECK_EQ(mRTPMode, TRANSPORT_TCP);

                if (mRTPClientSessionID != 0) {
                    // We only allow a single client connection.
                    mNetSession->destroySession(sessionID);
                    sessionID = 0;
                    break;
                }

                mRTPClientSessionID = sessionID;
                mRTPConnected = true;
            } else {
                CHECK_EQ(mRTCPMode, TRANSPORT_TCP);

                if (mRTCPClientSessionID != 0) {
                    // We only allow a single client connection.
                    mNetSession->destroySession(sessionID);
                    sessionID = 0;
                    break;
                }

                mRTCPClientSessionID = sessionID;
                mRTCPConnected = true;
            }

            if (mRTPConnected
                    && (mRTCPConnected || mRTCPMode == TRANSPORT_NONE)) {
                notifyInitDone(OK);
            }
            break;
        }
    }
}

void RTPReceiver::notifyInitDone(status_t err) {
    sp<AMessage> notify = mNotify->dup();
    notify->setInt32("what", kWhatInitDone);
    notify->setInt32("err", err);
    notify->post();
}

void RTPReceiver::notifyError(status_t err) {
    sp<AMessage> notify = mNotify->dup();
    notify->setInt32("what", kWhatError);
    notify->setInt32("err", err);
    notify->post();
}

void RTPReceiver::notifyPacketLost() {
    sp<AMessage> notify = mNotify->dup();
    notify->setInt32("what", kWhatPacketLost);
    notify->post();
}

status_t RTPReceiver::onRTPData(const sp<ABuffer> &buffer) {
    size_t size = buffer->size();
    if (size < 12) {
        // Too short to be a valid RTP header.
        return ERROR_MALFORMED;
    }

    const uint8_t *data = buffer->data();

    if ((data[0] >> 6) != 2) {
        // Unsupported version.
        return ERROR_UNSUPPORTED;
    }

    if (data[0] & 0x20) {
        // Padding present.

        size_t paddingLength = data[size - 1];

        if (paddingLength + 12 > size) {
            // If we removed this much padding we'd end up with something
            // that's too short to be a valid RTP header.
            return ERROR_MALFORMED;
        }

        size -= paddingLength;
    }

    int numCSRCs = data[0] & 0x0f;

    size_t payloadOffset = 12 + 4 * numCSRCs;

    if (size < payloadOffset) {
        // Not enough data to fit the basic header and all the CSRC entries.
        return ERROR_MALFORMED;
    }

    if (data[0] & 0x10) {
        // Header eXtension present.

        if (size < payloadOffset + 4) {
            // Not enough data to fit the basic header, all CSRC entries
            // and the first 4 bytes of the extension header.

            return ERROR_MALFORMED;
        }

        const uint8_t *extensionData = &data[payloadOffset];

        size_t extensionLength =
            4 * (extensionData[2] << 8 | extensionData[3]);

        if (size < payloadOffset + 4 + extensionLength) {
            return ERROR_MALFORMED;
        }

        payloadOffset += 4 + extensionLength;
    }

    uint32_t srcId = U32_AT(&data[8]);
    uint32_t rtpTime = U32_AT(&data[4]);
    uint16_t seqNo = U16_AT(&data[2]);

    sp<AMessage> meta = buffer->meta();
    meta->setInt32("ssrc", srcId);
    meta->setInt32("rtp-time", rtpTime);
    meta->setInt32("PT", data[1] & 0x7f);
    meta->setInt32("M", data[1] >> 7);

    buffer->setRange(payloadOffset, size - payloadOffset);

    ssize_t index = mSources.indexOfKey(srcId);
    sp<Source> source;
    if (index < 0) {
        source = new Source(this, srcId);
        looper()->registerHandler(source);

        mSources.add(srcId, source);
    } else {
        source = mSources.valueAt(index);
    }

    source->onPacketReceived(seqNo, buffer);

    return OK;
}

status_t RTPReceiver::onRTCPData(const sp<ABuffer> &data) {
    ALOGI("onRTCPData");
    return OK;
}

void RTPReceiver::addSDES(const sp<ABuffer> &buffer) {
    uint8_t *data = buffer->data() + buffer->size();
    data[0] = 0x80 | 1;
    data[1] = 202;  // SDES
    data[4] = kSourceID >> 24;  // SSRC
    data[5] = (kSourceID >> 16) & 0xff;
    data[6] = (kSourceID >> 8) & 0xff;
    data[7] = kSourceID & 0xff;

    size_t offset = 8;

    data[offset++] = 1;  // CNAME

    AString cname = "stagefright@somewhere";
    data[offset++] = cname.size();

    memcpy(&data[offset], cname.c_str(), cname.size());
    offset += cname.size();

    data[offset++] = 6;  // TOOL

    AString tool = "stagefright/1.0";
    data[offset++] = tool.size();

    memcpy(&data[offset], tool.c_str(), tool.size());
    offset += tool.size();

    data[offset++] = 0;

    if ((offset % 4) > 0) {
        size_t count = 4 - (offset % 4);
        switch (count) {
            case 3:
                data[offset++] = 0;
            case 2:
                data[offset++] = 0;
            case 1:
                data[offset++] = 0;
        }
    }

    size_t numWords = (offset / 4) - 1;
    data[2] = numWords >> 8;
    data[3] = numWords & 0xff;

    buffer->setRange(buffer->offset(), buffer->size() + offset);
}

void RTPReceiver::scheduleSendRR() {
    (new AMessage(kWhatSendRR, id()))->post(5000000ll);
}

void RTPReceiver::onSendRR() {
#if 0
    sp<ABuffer> buf = new ABuffer(kMaxUDPPacketSize);
    buf->setRange(0, 0);

    uint8_t *ptr = buf->data();
    ptr[0] = 0x80 | 0;
    ptr[1] = 201;  // RR
    ptr[2] = 0;
    ptr[3] = 1;
    ptr[4] = kSourceID >> 24;  // SSRC
    ptr[5] = (kSourceID >> 16) & 0xff;
    ptr[6] = (kSourceID >> 8) & 0xff;
    ptr[7] = kSourceID & 0xff;

    buf->setRange(0, 8);

    size_t numReportBlocks = 0;
    for (size_t i = 0; i < mSources.size(); ++i) {
        uint32_t ssrc = mSources.keyAt(i);
        sp<Source> source = mSources.valueAt(i);

        if (numReportBlocks > 31 || buf->size() + 24 > buf->capacity()) {
            // Cannot fit another report block.
            break;
        }

        source->addReportBlock(ssrc, buf);
        ++numReportBlocks;
    }

    ptr[0] |= numReportBlocks;  // 5 bit

    size_t sizeInWordsMinus1 = 1 + 6 * numReportBlocks;
    ptr[2] = sizeInWordsMinus1 >> 8;
    ptr[3] = sizeInWordsMinus1 & 0xff;

    buf->setRange(0, (sizeInWordsMinus1 + 1) * 4);

    addSDES(buf);

    mNetSession->sendRequest(mRTCPSessionID, buf->data(), buf->size());
#endif

    scheduleSendRR();
}

status_t RTPReceiver::registerPacketType(
        uint8_t packetType, PacketizationMode mode) {
    mPacketTypes.add(packetType, mode);

    return OK;
}

sp<RTPReceiver::Assembler> RTPReceiver::makeAssembler(uint8_t packetType) {
    ssize_t index = mPacketTypes.indexOfKey(packetType);
    if (index < 0) {
        return NULL;
    }

    PacketizationMode mode = mPacketTypes.valueAt(index);

    switch (mode) {
        case PACKETIZATION_NONE:
        case PACKETIZATION_TRANSPORT_STREAM:
            return new TSAssembler(mNotify);

        case PACKETIZATION_H264:
            return new H264Assembler(mNotify);

        default:
            return NULL;
    }
}

void RTPReceiver::requestRetransmission(uint32_t senderSSRC, int32_t extSeqNo) {
    int32_t blp = 0;

    sp<ABuffer> buf = new ABuffer(16);
    buf->setRange(0, 0);

    uint8_t *ptr = buf->data();
    ptr[0] = 0x80 | 1;  // generic NACK
    ptr[1] = 205;  // TSFB
    ptr[2] = 0;
    ptr[3] = 3;
    ptr[8] = (senderSSRC >> 24) & 0xff;
    ptr[9] = (senderSSRC >> 16) & 0xff;
    ptr[10] = (senderSSRC >> 8) & 0xff;
    ptr[11] = (senderSSRC & 0xff);
    ptr[8] = (kSourceID >> 24) & 0xff;
    ptr[9] = (kSourceID >> 16) & 0xff;
    ptr[10] = (kSourceID >> 8) & 0xff;
    ptr[11] = (kSourceID & 0xff);
    ptr[12] = (extSeqNo >> 8) & 0xff;
    ptr[13] = (extSeqNo & 0xff);
    ptr[14] = (blp >> 8) & 0xff;
    ptr[15] = (blp & 0xff);

    buf->setRange(0, 16);

     mNetSession->sendRequest(mRTCPSessionID, buf->data(), buf->size());
}

void RTPReceiver::Source::modifyPacketStatus(int32_t extSeqNo, uint32_t mask) {
#if TRACK_PACKET_LOSS
    ssize_t index = mLostPackets.indexOfKey(extSeqNo);
    if (index < 0) {
        mLostPackets.add(extSeqNo, mask);
    } else {
        mLostPackets.editValueAt(index) |= mask;
    }
#endif
}

void RTPReceiver::Source::postRetransmitTimer(int64_t timeUs) {
    int64_t delayUs = timeUs - ALooper::GetNowUs();
    sp<AMessage> msg = new AMessage(kWhatRetransmit, id());
    msg->setInt32("generation", mRetransmitGeneration);
    msg->post(delayUs);
}

void RTPReceiver::Source::postDeclareLostTimer(int64_t timeUs) {
    CHECK(!mDeclareLostTimerPending);
    mDeclareLostTimerPending = true;

    int64_t delayUs = timeUs - ALooper::GetNowUs();
    sp<AMessage> msg = new AMessage(kWhatDeclareLost, id());
    msg->setInt32("generation", mDeclareLostGeneration);
    msg->post(delayUs);
}

void RTPReceiver::Source::cancelTimers() {
    ++mRetransmitGeneration;
    ++mDeclareLostGeneration;
    mDeclareLostTimerPending = false;
}

}  // namespace android

