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

Commit efd9c63d authored by Andreas Huber's avatar Andreas Huber
Browse files

Code to support RTP retransmission according to rfc4585, rfc4588

Change-Id: Idfb3c0935f28e4cbc2141f0903f0d3c4e95818a6
parent 2761d21c
Loading
Loading
Loading
Loading
+152 −34
Original line number Diff line number Diff line
@@ -209,11 +209,18 @@ WifiDisplaySource::PlaybackSession::PlaybackSession(
      mRTPPort(0),
      mRTPSessionID(0),
      mRTCPSessionID(0),
#if ENABLE_RETRANSMISSION
      mRTPRetransmissionSessionID(0),
      mRTCPRetransmissionSessionID(0),
#endif
      mClientRTPPort(0),
      mClientRTCPPort(0),
      mRTPConnected(false),
      mRTCPConnected(false),
      mRTPSeqNo(0),
#if ENABLE_RETRANSMISSION
      mRTPRetransmissionSeqNo(0),
#endif
      mLastNTPTime(0),
      mLastRTPTime(0),
      mNumRTPSent(0),
@@ -279,6 +286,15 @@ status_t WifiDisplaySource::PlaybackSession::init(

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

#if ENABLE_RETRANSMISSION
    sp<AMessage> rtpRetransmissionNotify =
        new AMessage(kWhatRTPRetransmissionNotify, id());

    sp<AMessage> rtcpRetransmissionNotify =
        new AMessage(kWhatRTCPRetransmissionNotify, id());
#endif

    for (serverRtp = 15550;; serverRtp += 2) {
        int32_t rtpSession;
        if (mTransportMode == TRANSPORT_UDP) {
@@ -296,18 +312,9 @@ status_t WifiDisplaySource::PlaybackSession::init(
            continue;
        }

        if (clientRtcp < 0) {
            // No RTCP.

            mRTPPort = serverRtp;
            mRTPSessionID = rtpSession;
            mRTCPSessionID = 0;

            ALOGI("rtpSessionId = %d", rtpSession);
            break;
        }
        int32_t rtcpSession = 0;

        int32_t rtcpSession;
        if (clientRtcp >= 0) {
            if (mTransportMode == TRANSPORT_UDP) {
                err = mNetSession->createUDPSession(
                        serverRtp + 1, clientIP, clientRtcp,
@@ -318,7 +325,57 @@ status_t WifiDisplaySource::PlaybackSession::init(
                        rtcpNotify, &rtcpSession);
            }

        if (err == OK) {
            if (err != OK) {
                ALOGI("failed to create RTCP socket on port %d", serverRtp + 1);

                mNetSession->destroySession(rtpSession);
                continue;
            }
        }

#if ENABLE_RETRANSMISSION
        if (mTransportMode == TRANSPORT_UDP) {
            int32_t rtpRetransmissionSession;

            err = mNetSession->createUDPSession(
                        serverRtp + kRetransmissionPortOffset,
                        clientIP,
                        clientRtp + kRetransmissionPortOffset,
                        rtpRetransmissionNotify,
                        &rtpRetransmissionSession);

            if (err != OK) {
                mNetSession->destroySession(rtcpSession);
                mNetSession->destroySession(rtpSession);
                continue;
            }

            CHECK_GE(clientRtcp, 0);

            int32_t rtcpRetransmissionSession;
            err = mNetSession->createUDPSession(
                        serverRtp + 1 + kRetransmissionPortOffset,
                        clientIP,
                        clientRtp + 1 + kRetransmissionPortOffset,
                        rtcpRetransmissionNotify,
                        &rtcpRetransmissionSession);

            if (err != OK) {
                mNetSession->destroySession(rtpRetransmissionSession);
                mNetSession->destroySession(rtcpSession);
                mNetSession->destroySession(rtpSession);
                continue;
            }

            mRTPRetransmissionSessionID = rtpRetransmissionSession;
            mRTCPRetransmissionSessionID = rtcpRetransmissionSession;

            ALOGI("rtpRetransmissionSessionID = %d, "
                  "rtcpRetransmissionSessionID = %d",
                  rtpRetransmissionSession, rtcpRetransmissionSession);
        }
#endif

        mRTPPort = serverRtp;
        mRTPSessionID = rtpSession;
        mRTCPSessionID = rtcpSession;
@@ -327,10 +384,6 @@ status_t WifiDisplaySource::PlaybackSession::init(
        break;
    }

        ALOGI("failed to create RTCP socket on port %d", serverRtp + 1);
        mNetSession->destroySession(rtpSession);
    }

    if (mRTPPort == 0) {
        return UNKNOWN_ERROR;
    }
@@ -461,6 +514,16 @@ status_t WifiDisplaySource::PlaybackSession::destroy() {
        service->connectDisplay(NULL);
    }

#if ENABLE_RETRANSMISSION
    if (mRTCPRetransmissionSessionID != 0) {
        mNetSession->destroySession(mRTCPRetransmissionSessionID);
    }

    if (mRTPRetransmissionSessionID != 0) {
        mNetSession->destroySession(mRTPRetransmissionSessionID);
    }
#endif

    if (mRTCPSessionID != 0) {
        mNetSession->destroySession(mRTCPSessionID);
    }
@@ -477,6 +540,10 @@ void WifiDisplaySource::PlaybackSession::onMessageReceived(
    switch (msg->what()) {
        case kWhatRTPNotify:
        case kWhatRTCPNotify:
#if ENABLE_RETRANSMISSION
        case kWhatRTPRetransmissionNotify:
        case kWhatRTCPRetransmissionNotify:
#endif
        {
            int32_t reason;
            CHECK(msg->findInt32("reason", &reason));
@@ -496,8 +563,11 @@ void WifiDisplaySource::PlaybackSession::onMessageReceived(
                    AString detail;
                    CHECK(msg->findString("detail", &detail));

                    if (msg->what() == kWhatRTPNotify
                            && !errorOccuredDuringSend) {
                    if ((msg->what() == kWhatRTPNotify
#if ENABLE_RETRANSMISSION
                            || msg->what() == kWhatRTPRetransmissionNotify
#endif
                        ) && !errorOccuredDuringSend) {
                        // This is ok, we don't expect to receive anything on
                        // the RTP socket.
                        break;
@@ -518,6 +588,13 @@ void WifiDisplaySource::PlaybackSession::onMessageReceived(
                    } else if (sessionID == mRTCPSessionID) {
                        mRTCPSessionID = 0;
                    }
#if ENABLE_RETRANSMISSION
                    else if (sessionID == mRTPRetransmissionSessionID) {
                        mRTPRetransmissionSessionID = 0;
                    } else if (sessionID == mRTCPRetransmissionSessionID) {
                        mRTCPRetransmissionSessionID = 0;
                    }
#endif

                    // Inform WifiDisplaySource of our premature death (wish).
                    sp<AMessage> notify = mNotify->dup();
@@ -535,7 +612,12 @@ void WifiDisplaySource::PlaybackSession::onMessageReceived(
                    CHECK(msg->findBuffer("data", &data));

                    status_t err;
                    if (msg->what() == kWhatRTCPNotify) {
                    if (msg->what() == kWhatRTCPNotify
#if ENABLE_RETRANSMISSION
                            || msg->what() == kWhatRTCPRetransmissionNotify
#endif
                       )
                    {
                        err = parseRTCP(data);
                    }
                    break;
@@ -1293,9 +1375,11 @@ status_t WifiDisplaySource::PlaybackSession::parseRTCP(
            case 204:  // APP
                break;

#if ENABLE_RETRANSMISSION
            case 205:  // TSFB (transport layer specific feedback)
                parseTSFB(data, headerLength);
                break;
#endif

            case 206:  // PSFB (payload specific feedback)
                hexdump(data, headerLength);
@@ -1316,6 +1400,7 @@ status_t WifiDisplaySource::PlaybackSession::parseRTCP(
    return OK;
}

#if ENABLE_RETRANSMISSION
status_t WifiDisplaySource::PlaybackSession::parseTSFB(
        const uint8_t *data, size_t size) {
    if ((data[0] & 0x1f) != 1) {
@@ -1332,31 +1417,64 @@ status_t WifiDisplaySource::PlaybackSession::parseTSFB(
        uint16_t blp = U16_AT(&data[i + 2]);

        List<sp<ABuffer> >::iterator it = mHistory.begin();
        bool found = false;
        bool foundSeqNo = false;
        while (it != mHistory.end()) {
            const sp<ABuffer> &buffer = *it;

            uint16_t bufferSeqNo = buffer->int32Data() & 0xffff;

            bool retransmit = false;
            if (bufferSeqNo == seqNo) {
                retransmit = true;
            } else if (blp != 0) {
                for (size_t i = 0; i < 16; ++i) {
                    if ((blp & (1 << i))
                        && (bufferSeqNo == ((seqNo + i + 1) & 0xffff))) {
                        blp &= ~(1 << i);
                        retransmit = true;
                    }
                }
            }

            if (retransmit) {
                ALOGI("retransmitting seqNo %d", bufferSeqNo);

                sp<ABuffer> retransRTP = new ABuffer(2 + buffer->size());
                uint8_t *rtp = retransRTP->data();
                memcpy(rtp, buffer->data(), 12);
                rtp[2] = (mRTPRetransmissionSeqNo >> 8) & 0xff;
                rtp[3] = mRTPRetransmissionSeqNo & 0xff;
                rtp[12] = (bufferSeqNo >> 8) & 0xff;
                rtp[13] = bufferSeqNo & 0xff;
                memcpy(&rtp[14], buffer->data() + 12, buffer->size() - 12);

                ++mRTPRetransmissionSeqNo;

                sendPacket(
                        mRTPRetransmissionSessionID,
                        retransRTP->data(), retransRTP->size());

                if (bufferSeqNo == seqNo) {
                sendPacket(mRTPSessionID, buffer->data(), buffer->size());
                    foundSeqNo = true;
                }

                found = true;
                if (foundSeqNo && blp == 0) {
                    break;
                }
            }

            ++it;
        }

        if (found) {
            ALOGI("retransmitting seqNo %d", seqNo);
        } else {
            ALOGI("seqNo %d no longer available", seqNo);
        if (!foundSeqNo || blp != 0) {
            ALOGI("Some sequence numbers were no longer available for "
                  "retransmission");
        }
    }

    return OK;
}
#endif

void WifiDisplaySource::PlaybackSession::requestIDRFrame() {
    for (size_t i = 0; i < mTracks.size(); ++i) {
+21 −1
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ struct Serializer;
struct TSPacketizer;

#define LOG_TRANSPORT_STREAM            0
#define ENABLE_RETRANSMISSION           0

// Encapsulates the state of an RTP/RTCP session in the context of wifi
// display.
@@ -86,6 +87,10 @@ private:
        kWhatSendSR,
        kWhatRTPNotify,
        kWhatRTCPNotify,
#if ENABLE_RETRANSMISSION
        kWhatRTPRetransmissionNotify,
        kWhatRTCPRetransmissionNotify,
#endif
        kWhatSerializerNotify,
        kWhatConverterNotify,
        kWhatUpdateSurface,
@@ -96,6 +101,10 @@ private:
    static const uint32_t kSourceID = 0xdeadbeef;
    static const size_t kMaxHistoryLength = 128;

#if ENABLE_RETRANSMISSION
    static const size_t kRetransmissionPortOffset = 120;
#endif

    sp<ANetworkSession> mNetSession;
    sp<AMessage> mNotify;
    in_addr mInterfaceAddr;
@@ -128,12 +137,20 @@ private:
    int32_t mRTPSessionID;
    int32_t mRTCPSessionID;

#if ENABLE_RETRANSMISSION
    int32_t mRTPRetransmissionSessionID;
    int32_t mRTCPRetransmissionSessionID;
#endif

    int32_t mClientRTPPort;
    int32_t mClientRTCPPort;
    bool mRTPConnected;
    bool mRTCPConnected;

    uint32_t mRTPSeqNo;
#if ENABLE_RETRANSMISSION
    uint32_t mRTPRetransmissionSeqNo;
#endif

    uint64_t mLastNTPTime;
    uint32_t mLastRTPTime;
@@ -177,7 +194,10 @@ private:
    void scheduleSendSR();

    status_t parseRTCP(const sp<ABuffer> &buffer);

#if ENABLE_RETRANSMISSION
    status_t parseTSFB(const uint8_t *data, size_t size);
#endif

    status_t sendPacket(int32_t sessionID, const void *data, size_t size);
    status_t onFinishPlay();
+1 −0
Original line number Diff line number Diff line
@@ -869,6 +869,7 @@ status_t WifiDisplaySource::onSetupRequest(
        } else if (sscanf(clientPort.c_str(), "%d", &clientRtp) == 1) {
            // No RTCP.
            clientRtcp = -1;
            clientRtcp = clientRtp + 1;  // XXX
        } else {
            badRequest = true;
        }