summaryrefslogtreecommitdiffstats
path: root/media/libstagefright/wifi-display/rtp
diff options
context:
space:
mode:
authorAndreas Huber <andih@google.com>2013-04-26 08:42:50 -0700
committerAndreas Huber <andih@google.com>2013-04-26 08:42:50 -0700
commitc86ef45279185b474bd6af0a7ae407f8ab577f13 (patch)
tree110e05de886cf816f0b9265931c611f74d668b8b /media/libstagefright/wifi-display/rtp
parentc540ea00f4763758c9c40594d1e086aeefda9b70 (diff)
downloadframeworks_av-c86ef45279185b474bd6af0a7ae407f8ab577f13.zip
frameworks_av-c86ef45279185b474bd6af0a7ae407f8ab577f13.tar.gz
frameworks_av-c86ef45279185b474bd6af0a7ae407f8ab577f13.tar.bz2
Revert "Remove all traces of wifi display sink implementation and supporting code."
This reverts commit 3a9682a86ead84d6f60d3f3aa01b2b4d34af983d.
Diffstat (limited to 'media/libstagefright/wifi-display/rtp')
-rw-r--r--media/libstagefright/wifi-display/rtp/RTPAssembler.cpp328
-rw-r--r--media/libstagefright/wifi-display/rtp/RTPAssembler.h92
-rw-r--r--media/libstagefright/wifi-display/rtp/RTPReceiver.cpp1153
-rw-r--r--media/libstagefright/wifi-display/rtp/RTPReceiver.h125
-rw-r--r--media/libstagefright/wifi-display/rtp/RTPSender.cpp11
-rw-r--r--media/libstagefright/wifi-display/rtp/RTPSender.h1
6 files changed, 1710 insertions, 0 deletions
diff --git a/media/libstagefright/wifi-display/rtp/RTPAssembler.cpp b/media/libstagefright/wifi-display/rtp/RTPAssembler.cpp
new file mode 100644
index 0000000..7a96081
--- /dev/null
+++ b/media/libstagefright/wifi-display/rtp/RTPAssembler.cpp
@@ -0,0 +1,328 @@
+/*
+ * 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 "RTPAssembler"
+#include <utils/Log.h>
+
+#include "RTPAssembler.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>
+
+namespace android {
+
+RTPReceiver::Assembler::Assembler(const sp<AMessage> &notify)
+ : mNotify(notify) {
+}
+
+void RTPReceiver::Assembler::postAccessUnit(
+ const sp<ABuffer> &accessUnit, bool followsDiscontinuity) {
+ sp<AMessage> notify = mNotify->dup();
+ notify->setInt32("what", RTPReceiver::kWhatAccessUnit);
+ notify->setBuffer("accessUnit", accessUnit);
+ notify->setInt32("followsDiscontinuity", followsDiscontinuity);
+ notify->post();
+}
+////////////////////////////////////////////////////////////////////////////////
+
+RTPReceiver::TSAssembler::TSAssembler(const sp<AMessage> &notify)
+ : Assembler(notify),
+ mSawDiscontinuity(false) {
+}
+
+void RTPReceiver::TSAssembler::signalDiscontinuity() {
+ mSawDiscontinuity = true;
+}
+
+status_t RTPReceiver::TSAssembler::processPacket(const sp<ABuffer> &packet) {
+ int32_t rtpTime;
+ CHECK(packet->meta()->findInt32("rtp-time", &rtpTime));
+
+ packet->meta()->setInt64("timeUs", (rtpTime * 100ll) / 9);
+
+ postAccessUnit(packet, mSawDiscontinuity);
+
+ if (mSawDiscontinuity) {
+ mSawDiscontinuity = false;
+ }
+
+ return OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+RTPReceiver::H264Assembler::H264Assembler(const sp<AMessage> &notify)
+ : Assembler(notify),
+ mState(0),
+ mIndicator(0),
+ mNALType(0),
+ mAccessUnitRTPTime(0) {
+}
+
+void RTPReceiver::H264Assembler::signalDiscontinuity() {
+ reset();
+}
+
+status_t RTPReceiver::H264Assembler::processPacket(const sp<ABuffer> &packet) {
+ status_t err = internalProcessPacket(packet);
+
+ if (err != OK) {
+ reset();
+ }
+
+ return err;
+}
+
+status_t RTPReceiver::H264Assembler::internalProcessPacket(
+ const sp<ABuffer> &packet) {
+ const uint8_t *data = packet->data();
+ size_t size = packet->size();
+
+ switch (mState) {
+ case 0:
+ {
+ if (size < 1 || (data[0] & 0x80)) {
+ ALOGV("Malformed H264 RTP packet (empty or F-bit set)");
+ return ERROR_MALFORMED;
+ }
+
+ unsigned nalType = data[0] & 0x1f;
+ if (nalType >= 1 && nalType <= 23) {
+ addSingleNALUnit(packet);
+ ALOGV("added single NAL packet");
+ } else if (nalType == 28) {
+ // FU-A
+ unsigned indicator = data[0];
+ CHECK((indicator & 0x1f) == 28);
+
+ if (size < 2) {
+ ALOGV("Malformed H264 FU-A packet (single byte)");
+ return ERROR_MALFORMED;
+ }
+
+ if (!(data[1] & 0x80)) {
+ ALOGV("Malformed H264 FU-A packet (no start bit)");
+ return ERROR_MALFORMED;
+ }
+
+ mIndicator = data[0];
+ mNALType = data[1] & 0x1f;
+ uint32_t nri = (data[0] >> 5) & 3;
+
+ clearAccumulator();
+
+ uint8_t byte = mNALType | (nri << 5);
+ appendToAccumulator(&byte, 1);
+ appendToAccumulator(data + 2, size - 2);
+
+ int32_t rtpTime;
+ CHECK(packet->meta()->findInt32("rtp-time", &rtpTime));
+ mAccumulator->meta()->setInt32("rtp-time", rtpTime);
+
+ if (data[1] & 0x40) {
+ // Huh? End bit also set on the first buffer.
+ addSingleNALUnit(mAccumulator);
+ clearAccumulator();
+
+ ALOGV("added FU-A");
+ break;
+ }
+
+ mState = 1;
+ } else if (nalType == 24) {
+ // STAP-A
+
+ status_t err = addSingleTimeAggregationPacket(packet);
+ if (err != OK) {
+ return err;
+ }
+ } else {
+ ALOGV("Malformed H264 packet (unknown type %d)", nalType);
+ return ERROR_UNSUPPORTED;
+ }
+ break;
+ }
+
+ case 1:
+ {
+ if (size < 2
+ || data[0] != mIndicator
+ || (data[1] & 0x1f) != mNALType
+ || (data[1] & 0x80)) {
+ ALOGV("Malformed H264 FU-A packet (indicator, "
+ "type or start bit mismatch)");
+
+ return ERROR_MALFORMED;
+ }
+
+ appendToAccumulator(data + 2, size - 2);
+
+ if (data[1] & 0x40) {
+ addSingleNALUnit(mAccumulator);
+
+ clearAccumulator();
+ mState = 0;
+
+ ALOGV("added FU-A");
+ }
+ break;
+ }
+
+ default:
+ TRESPASS();
+ }
+
+ int32_t marker;
+ CHECK(packet->meta()->findInt32("M", &marker));
+
+ if (marker) {
+ flushAccessUnit();
+ }
+
+ return OK;
+}
+
+void RTPReceiver::H264Assembler::reset() {
+ mNALUnits.clear();
+
+ clearAccumulator();
+ mState = 0;
+}
+
+void RTPReceiver::H264Assembler::clearAccumulator() {
+ if (mAccumulator != NULL) {
+ // XXX Too expensive.
+ mAccumulator.clear();
+ }
+}
+
+void RTPReceiver::H264Assembler::appendToAccumulator(
+ const void *data, size_t size) {
+ if (mAccumulator == NULL) {
+ mAccumulator = new ABuffer(size);
+ memcpy(mAccumulator->data(), data, size);
+ return;
+ }
+
+ if (mAccumulator->size() + size > mAccumulator->capacity()) {
+ sp<ABuffer> buf = new ABuffer(mAccumulator->size() + size);
+ memcpy(buf->data(), mAccumulator->data(), mAccumulator->size());
+ buf->setRange(0, mAccumulator->size());
+
+ int32_t rtpTime;
+ if (mAccumulator->meta()->findInt32("rtp-time", &rtpTime)) {
+ buf->meta()->setInt32("rtp-time", rtpTime);
+ }
+
+ mAccumulator = buf;
+ }
+
+ memcpy(mAccumulator->data() + mAccumulator->size(), data, size);
+ mAccumulator->setRange(0, mAccumulator->size() + size);
+}
+
+void RTPReceiver::H264Assembler::addSingleNALUnit(const sp<ABuffer> &packet) {
+ if (mNALUnits.empty()) {
+ int32_t rtpTime;
+ CHECK(packet->meta()->findInt32("rtp-time", &rtpTime));
+
+ mAccessUnitRTPTime = rtpTime;
+ }
+
+ mNALUnits.push_back(packet);
+}
+
+void RTPReceiver::H264Assembler::flushAccessUnit() {
+ if (mNALUnits.empty()) {
+ return;
+ }
+
+ size_t totalSize = 0;
+ for (List<sp<ABuffer> >::iterator it = mNALUnits.begin();
+ it != mNALUnits.end(); ++it) {
+ totalSize += 4 + (*it)->size();
+ }
+
+ sp<ABuffer> accessUnit = new ABuffer(totalSize);
+ size_t offset = 0;
+ for (List<sp<ABuffer> >::iterator it = mNALUnits.begin();
+ it != mNALUnits.end(); ++it) {
+ const sp<ABuffer> nalUnit = *it;
+
+ memcpy(accessUnit->data() + offset, "\x00\x00\x00\x01", 4);
+
+ memcpy(accessUnit->data() + offset + 4,
+ nalUnit->data(),
+ nalUnit->size());
+
+ offset += 4 + nalUnit->size();
+ }
+
+ mNALUnits.clear();
+
+ accessUnit->meta()->setInt64("timeUs", mAccessUnitRTPTime * 100ll / 9ll);
+ postAccessUnit(accessUnit, false /* followsDiscontinuity */);
+}
+
+status_t RTPReceiver::H264Assembler::addSingleTimeAggregationPacket(
+ const sp<ABuffer> &packet) {
+ const uint8_t *data = packet->data();
+ size_t size = packet->size();
+
+ if (size < 3) {
+ ALOGV("Malformed H264 STAP-A packet (too small)");
+ return ERROR_MALFORMED;
+ }
+
+ int32_t rtpTime;
+ CHECK(packet->meta()->findInt32("rtp-time", &rtpTime));
+
+ ++data;
+ --size;
+ while (size >= 2) {
+ size_t nalSize = (data[0] << 8) | data[1];
+
+ if (size < nalSize + 2) {
+ ALOGV("Malformed H264 STAP-A packet (incomplete NAL unit)");
+ return ERROR_MALFORMED;
+ }
+
+ sp<ABuffer> unit = new ABuffer(nalSize);
+ memcpy(unit->data(), &data[2], nalSize);
+
+ unit->meta()->setInt32("rtp-time", rtpTime);
+
+ addSingleNALUnit(unit);
+
+ data += 2 + nalSize;
+ size -= 2 + nalSize;
+ }
+
+ if (size != 0) {
+ ALOGV("Unexpected padding at end of STAP-A packet.");
+ }
+
+ ALOGV("added STAP-A");
+
+ return OK;
+}
+
+} // namespace android
+
diff --git a/media/libstagefright/wifi-display/rtp/RTPAssembler.h b/media/libstagefright/wifi-display/rtp/RTPAssembler.h
new file mode 100644
index 0000000..e456d32
--- /dev/null
+++ b/media/libstagefright/wifi-display/rtp/RTPAssembler.h
@@ -0,0 +1,92 @@
+/*
+ * 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.
+ */
+
+#ifndef RTP_ASSEMBLER_H_
+
+#define RTP_ASSEMBLER_H_
+
+#include "RTPReceiver.h"
+
+namespace android {
+
+// A helper class to reassemble the payload of RTP packets into access
+// units depending on the packetization scheme.
+struct RTPReceiver::Assembler : public RefBase {
+ Assembler(const sp<AMessage> &notify);
+
+ virtual void signalDiscontinuity() = 0;
+ virtual status_t processPacket(const sp<ABuffer> &packet) = 0;
+
+protected:
+ virtual ~Assembler() {}
+
+ void postAccessUnit(
+ const sp<ABuffer> &accessUnit, bool followsDiscontinuity);
+
+private:
+ sp<AMessage> mNotify;
+
+ DISALLOW_EVIL_CONSTRUCTORS(Assembler);
+};
+
+struct RTPReceiver::TSAssembler : public RTPReceiver::Assembler {
+ TSAssembler(const sp<AMessage> &notify);
+
+ virtual void signalDiscontinuity();
+ virtual status_t processPacket(const sp<ABuffer> &packet);
+
+private:
+ bool mSawDiscontinuity;
+
+ DISALLOW_EVIL_CONSTRUCTORS(TSAssembler);
+};
+
+struct RTPReceiver::H264Assembler : public RTPReceiver::Assembler {
+ H264Assembler(const sp<AMessage> &notify);
+
+ virtual void signalDiscontinuity();
+ virtual status_t processPacket(const sp<ABuffer> &packet);
+
+private:
+ int32_t mState;
+
+ uint8_t mIndicator;
+ uint8_t mNALType;
+
+ sp<ABuffer> mAccumulator;
+
+ List<sp<ABuffer> > mNALUnits;
+ int32_t mAccessUnitRTPTime;
+
+ status_t internalProcessPacket(const sp<ABuffer> &packet);
+
+ void addSingleNALUnit(const sp<ABuffer> &packet);
+ status_t addSingleTimeAggregationPacket(const sp<ABuffer> &packet);
+
+ void flushAccessUnit();
+
+ void clearAccumulator();
+ void appendToAccumulator(const void *data, size_t size);
+
+ void reset();
+
+ DISALLOW_EVIL_CONSTRUCTORS(H264Assembler);
+};
+
+} // namespace android
+
+#endif // RTP_ASSEMBLER_H_
+
diff --git a/media/libstagefright/wifi-display/rtp/RTPReceiver.cpp b/media/libstagefright/wifi-display/rtp/RTPReceiver.cpp
new file mode 100644
index 0000000..8fa1dae
--- /dev/null
+++ b/media/libstagefright/wifi-display/rtp/RTPReceiver.cpp
@@ -0,0 +1,1153 @@
+/*
+ * 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
+
diff --git a/media/libstagefright/wifi-display/rtp/RTPReceiver.h b/media/libstagefright/wifi-display/rtp/RTPReceiver.h
new file mode 100644
index 0000000..240ab2e
--- /dev/null
+++ b/media/libstagefright/wifi-display/rtp/RTPReceiver.h
@@ -0,0 +1,125 @@
+/*
+ * 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.
+ */
+
+#ifndef RTP_RECEIVER_H_
+
+#define RTP_RECEIVER_H_
+
+#include "RTPBase.h"
+
+#include <media/stagefright/foundation/AHandler.h>
+
+namespace android {
+
+struct ABuffer;
+struct ANetworkSession;
+
+// An object of this class facilitates receiving of media data on an RTP
+// channel. The channel is established over a UDP or TCP connection depending
+// on which "TransportMode" was chosen. In addition different RTP packetization
+// schemes are supported such as "Transport Stream Packets over RTP",
+// or "AVC/H.264 encapsulation as specified in RFC 3984 (non-interleaved mode)"
+struct RTPReceiver : public RTPBase, public AHandler {
+ enum {
+ kWhatInitDone,
+ kWhatError,
+ kWhatAccessUnit,
+ kWhatPacketLost,
+ };
+
+ enum Flags {
+ FLAG_AUTO_CONNECT = 1,
+ };
+ RTPReceiver(
+ const sp<ANetworkSession> &netSession,
+ const sp<AMessage> &notify,
+ uint32_t flags = 0);
+
+ status_t registerPacketType(
+ uint8_t packetType, PacketizationMode mode);
+
+ status_t initAsync(
+ TransportMode rtpMode,
+ TransportMode rtcpMode,
+ int32_t *outLocalRTPPort);
+
+ status_t connect(
+ const char *remoteHost,
+ int32_t remoteRTPPort,
+ int32_t remoteRTCPPort);
+
+ status_t informSender(const sp<AMessage> &params);
+
+protected:
+ virtual ~RTPReceiver();
+ virtual void onMessageReceived(const sp<AMessage> &msg);
+
+private:
+ enum {
+ kWhatRTPNotify,
+ kWhatRTCPNotify,
+ kWhatSendRR,
+ };
+
+ enum {
+ kSourceID = 0xdeadbeef,
+ kPacketLostAfterUs = 100000,
+ kRequestRetransmissionAfterUs = -1,
+ };
+
+ struct Assembler;
+ struct H264Assembler;
+ struct Source;
+ struct TSAssembler;
+
+ sp<ANetworkSession> mNetSession;
+ sp<AMessage> mNotify;
+ uint32_t mFlags;
+ TransportMode mRTPMode;
+ TransportMode mRTCPMode;
+ int32_t mRTPSessionID;
+ int32_t mRTCPSessionID;
+ bool mRTPConnected;
+ bool mRTCPConnected;
+
+ int32_t mRTPClientSessionID; // in TRANSPORT_TCP mode.
+ int32_t mRTCPClientSessionID; // in TRANSPORT_TCP mode.
+
+ KeyedVector<uint8_t, PacketizationMode> mPacketTypes;
+ KeyedVector<uint32_t, sp<Source> > mSources;
+
+ void onNetNotify(bool isRTP, const sp<AMessage> &msg);
+ status_t onRTPData(const sp<ABuffer> &data);
+ status_t onRTCPData(const sp<ABuffer> &data);
+ void onSendRR();
+
+ void scheduleSendRR();
+ void addSDES(const sp<ABuffer> &buffer);
+
+ void notifyInitDone(status_t err);
+ void notifyError(status_t err);
+ void notifyPacketLost();
+
+ sp<Assembler> makeAssembler(uint8_t packetType);
+
+ void requestRetransmission(uint32_t senderSSRC, int32_t extSeqNo);
+
+ DISALLOW_EVIL_CONSTRUCTORS(RTPReceiver);
+};
+
+} // namespace android
+
+#endif // RTP_RECEIVER_H_
diff --git a/media/libstagefright/wifi-display/rtp/RTPSender.cpp b/media/libstagefright/wifi-display/rtp/RTPSender.cpp
index 095fd97..6bbe650 100644
--- a/media/libstagefright/wifi-display/rtp/RTPSender.cpp
+++ b/media/libstagefright/wifi-display/rtp/RTPSender.cpp
@@ -767,6 +767,17 @@ status_t RTPSender::parseTSFB(const uint8_t *data, size_t size) {
}
status_t RTPSender::parseAPP(const uint8_t *data, size_t size) {
+ if (!memcmp("late", &data[8], 4)) {
+ int64_t avgLatencyUs = (int64_t)U64_AT(&data[12]);
+ int64_t maxLatencyUs = (int64_t)U64_AT(&data[20]);
+
+ sp<AMessage> notify = mNotify->dup();
+ notify->setInt32("what", kWhatInformSender);
+ notify->setInt64("avgLatencyUs", avgLatencyUs);
+ notify->setInt64("maxLatencyUs", maxLatencyUs);
+ notify->post();
+ }
+
return OK;
}
diff --git a/media/libstagefright/wifi-display/rtp/RTPSender.h b/media/libstagefright/wifi-display/rtp/RTPSender.h
index 7dc138a..fefcab7 100644
--- a/media/libstagefright/wifi-display/rtp/RTPSender.h
+++ b/media/libstagefright/wifi-display/rtp/RTPSender.h
@@ -37,6 +37,7 @@ struct RTPSender : public RTPBase, public AHandler {
kWhatInitDone,
kWhatError,
kWhatNetworkStall,
+ kWhatInformSender,
};
RTPSender(
const sp<ANetworkSession> &netSession,